优化OSD文字描边的实现

serial
BlueMatthew 1 year ago
parent 6ef0f3b652
commit c42c0352ba

@ -99,7 +99,7 @@ namespace cv {
void putText(
InputOutputArray img, const String& text, Point org,
int fontHeight, Scalar color,
int thickness, int line_type, bool bottomLeftOrigin
int thickness, int line_type, bool bottomLeftOrigin, bool usingStroker
);
Size getTextSize(const String& text, int fontHeight, int thickness, CV_OUT int* baseLine);
@ -241,7 +241,7 @@ namespace cv {
void FreeType2Impl::putText(
InputOutputArray _img, const String& _text, Point _org,
int _fontHeight, Scalar _color,
int _thickness, int _line_type, bool _bottomLeftOrigin
int _thickness, int _line_type, bool _bottomLeftOrigin, bool usingStroker
)
{
CV_Assert(mIsFaceAvailable == true);
@ -279,9 +279,15 @@ namespace cv {
}
}
else {
// putTextOutline(_img, _text, _org, _fontHeight, _color, _thickness, _line_type, _bottomLeftOrigin);
if (usingStroker)
{
putTextStroker(_img, _text, _org, _fontHeight, _color, _thickness, _line_type, _bottomLeftOrigin);
}
else
{
putTextOutline(_img, _text, _org, _fontHeight, _color, _thickness, _line_type, _bottomLeftOrigin);
}
}
}
void FreeType2Impl::putTextOutline(
@ -302,6 +308,7 @@ namespace cv {
hb_buffer_get_glyph_infos(hb_buffer, &textLen);
CV_Assert(info != NULL);
#else
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
wstring wstr = converter.from_bytes(_text);
#endif
@ -327,6 +334,7 @@ namespace cv {
CV_Assert(!FT_Load_Glyph(mFace, info[i].codepoint, 0));
#else
for (unsigned int i = 0; i < wstr.size(); i++) {
wchar_t ch = wstr[i];
CV_Assert(!FT_Load_Glyph(mFace, FT_Get_Char_Index(mFace, wstr[i]), 0));
#endif
FT_GlyphSlot slot = mFace->glyph;
@ -408,8 +416,9 @@ namespace cv {
bbox.xMax = bbox.yMax = -32000;
// Get some metrics of our image.
// int imgWidth = mat.cols;
int imgWidth = mat.cols;
// _color.
cv::Vec3b outlineColor = cv::Vec3b(255 - (uchar)_color[0], 255 - (uchar)_color[1], 255 - (uchar)_color[2]);
cv::Vec3b fontColor = cv::Vec3b((uchar)_color[0], (uchar)_color[1], (uchar)_color[2]);
@ -540,9 +549,14 @@ namespace cv {
// int row = (imgHeight - 1 - (s->y - rect.ymin)) - imgHeight + (rect.ymax - rect.ymin);
// int row = (imgHeight - 1 - (s->y - rect.ymin));
int row = (bbox.yMax - bbox.yMin) - (s->y - rect.ymin) + _org.y - offsetY;
int col = s->x - rect.xmin + w + _org.x + bearingX;
if (row < 0 || col < 0 || row >= imgHeight || col >= imgWidth)
{
continue;
}
// int row = ((bbox.yMax - bbox.yMin) - (glyph_bbox.yMax - glyph_bbox.yMin)) / 2 - (s->y - rect.ymin) + _org.y;
// mat.at<Vec3b>((imgHeight - 1 - (s->y - rect.ymin)), s->x - rect.xmin + w) = outlineColor;
mat.at<Vec3b>(row, s->x - rect.xmin + w + _org.x + bearingX) = outlineColor;
mat.at<Vec3b>(row, col) = outlineColor;
// mat.at<Vec3b>(-(s->y - rect.ymin), s->x - rect.xmin + w) = outlineColor;
// vec3b.
/*
@ -562,6 +576,11 @@ namespace cv {
{
// int row = (imgHeight - 1 - (s->y - rect.ymin)) - imgHeight + (rect.ymax - rect.ymin);
int row = (bbox.yMax - bbox.yMin) - (s->y - rect.ymin) + _org.y - offsetY;
int col = s->x - rect.xmin + w + _org.x + bearingX;
if (row < 0 || col < 0 || row >= imgHeight || col >= imgWidth)
{
continue;
}
// int row = ((bbox.yMax - bbox.yMin) - (glyph_bbox.yMax - glyph_bbox.yMin)) / 2 - (s->y - rect.ymin) + _org.y;
mat.at<Vec3b>(row, s->x - rect.xmin + w + _org.x + bearingX) = fontColor;
// mat.at<Vec3b>(-(s->y - rect.ymin), s->x - rect.xmin + w) = fontColor;
@ -913,6 +932,7 @@ namespace cv {
CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
FT_Vector currentPos = { 0,0 };
FT_Set_Transform(mFace, 0, &currentPos);
#if defined(USING_HB)
hb_buffer_t *hb_buffer = hb_buffer_create();
CV_Assert(hb_buffer != NULL);

@ -52,8 +52,12 @@ namespace cv {
@param line_type Line type. See the line for details.
@param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
*/
virtual void putText(InputOutputArray img, const String& text, Point org, int fontHeight, Scalar color, int thickness, int line_type, bool bottomLeftOrigin)
{
putText(img, text, org, fontHeight, color, thickness, line_type, bottomLeftOrigin, false);
}
virtual void putText(InputOutputArray img, const String& text, Point org, int fontHeight, Scalar color, int thickness, int line_type, bool bottomLeftOrigin) = 0;
virtual void putText(InputOutputArray img, const String& text, Point org, int fontHeight, Scalar color, int thickness, int line_type, bool bottomLeftOrigin, bool usingStroker) = 0;
/** @brief Calculates the width and height of a text string.

@ -941,10 +941,10 @@ void DrawOutlineText(cv::Ptr<cv::ft::FreeType2> ft2, cv::Mat& mat, const std::st
textSize = ft2->getTextSize(*it, fontSize, thickness, &baseline);
lineHeight = std::max(lineHeight, textSize.height);
ft2->putText(mat, *it, pt, fontSize, clr, thickness, cv::LINE_AA, false);
ft2->putText(mat, *it, pt, fontSize, clr, thickness, cv::LINE_AA, false, true);
pt.x = startPoint.x;
pt.y += lineHeight > 0 ? (lineHeight + 2) : 0;
pt.y += lineHeight > 0 ? (lineHeight + fontSize / 5) : 0;
}
}
@ -958,13 +958,11 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
mPhotoInfo.photoTime = time(NULL);
int baseline = 0;
cv::Size textSize, textSize2;
double fontScale = 1; // base 1024
cv::Size textSize;
double height = mat.size().height;
double width = mat.size().width;
// double ratio = std::min(height / 1024, width / 1920);
double ratio = std::sqrt((height * width) / (1024.0 * 1920.0));
fontScale = fontScale * ratio;
double ratio = height / 1024.0;
// cv::Rect rc(0, 0, mat.cols, mat.rows);
// cv::rectangle (mat, rc, cv::Scalar(255, 255, 255), cv::FILLED);
@ -1023,13 +1021,25 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
}
}
int thickness = 4 * ratio;
int thickness = (int)(4.0 * ratio);
if (thickness < 2) thickness = 2;
cv::Scalar scalar(255, 255, 255); // white
int fontSize = 24;
std::string fontPath = m_appPath+ "fonts/Noto.ttf";
int fontSize = (int)(24.0 * ratio);
std::string fontPath;
if (existsFile("/system/fonts/NotoSansCJK-Regular.ttc"))
{
fontPath = "/system/fonts/NotoSansCJK-Regular.ttc";
}
else if (existsFile("/system/fonts/NotoSerifCJK-Regular.ttc"))
{
fontPath = "/system/fonts/NotoSerifCJK-Regular.ttc";
}
else
{
fontPath = m_appPath+ "fonts/Noto.otf";
}
cv::Ptr<cv::ft::FreeType2> ft2;
ft2 = cv::ft::createFreeType2();
ft2->loadFontData(fontPath.c_str(), 0);
@ -1040,7 +1050,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
NdkCamera::CAPTURE_RESULT captureResult = mCamera->getCaptureResult();
char str[128] = { 0 };
snprintf(str, sizeof(str), "AE=%u EXPS=%ums ISO=%d AF=%u FD=%.3f AFS=%u HDR=%d", captureResult.autoExposure,
snprintf(str, sizeof(str), "通道 AE=%u EXPS=%ums ISO=%d AF=%u FD=%.3f AFS=%u HDR=%d", captureResult.autoExposure,
(unsigned int)(captureResult.exposureTime / 1000000),
captureResult.sensitibity,
captureResult.autoFocus,
@ -1050,8 +1060,8 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
// cv::putText(mat, str, cv::Point(0, mat.rows - 20), cv::FONT_HERSHEY_COMPLEX, fontScale, scalar, thickness1, cv::LINE_AA);
ft2->putText(mat, str, cv::Point(0, mat.rows - 48),
fontSize, scalarRed, thickness, cv::LINE_AA, false);
ft2->putText(mat, str, cv::Point(0, mat.rows - fontSize - 20),
fontSize, scalarRed, -1, cv::LINE_AA, false);
// text.putText(mat, str.c_str(), cv::Point(0, mat.rows - 20), scalar);
@ -1062,7 +1072,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
#endif
cv::Point pt1, pt2;
cv::Point pt;
for (vector<OSD_INFO>::const_iterator it = mOsds.cbegin(); it != mOsds.cend(); ++it)
{
if (it->text.empty())
@ -1070,38 +1080,37 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
continue;
}
#ifdef _DEBUG
if (it->alignment == OSD_ALIGNMENT_BOTTOM_RIGHT)
{
int aa = 0;
}
#endif
textSize = ft2->getTextSize(it->text, fontSize, thickness, &baseline);
XYLOG(XYLOG_SEVERITY_DEBUG, "%s font Size=%d height: %d baseline=%d", it->text.c_str(), fontSize, textSize.height, baseline);
if (it->alignment == OSD_ALIGNMENT_TOP_LEFT)
{
pt1.x = it->x * ratio;
pt1.y = it->y * ratio + textSize.height;
pt.x = it->x * ratio;
pt.y = it->y * ratio;
}
else if (it->alignment == OSD_ALIGNMENT_TOP_RIGHT)
{
pt1.x = width - textSize.width - it->x * ratio;
pt1.y= it->y * ratio + textSize.height;
pt.x = width - textSize.width - it->x * ratio;
pt.y= it->y * ratio;
}
else if (it->alignment == OSD_ALIGNMENT_BOTTOM_RIGHT)
{
pt1.x = width - textSize.width - it->x * ratio;
pt1.y = height - it->y * ratio;
pt.x = width - textSize.width - it->x * ratio;
pt.y = height - it->y * ratio - textSize.height;
}
else if (it->alignment == OSD_ALIGNMENT_BOTTOM_LEFT)
{
pt1.x = it->x * ratio;
pt1.y = height - it->y * ratio;
pt.x = it->x * ratio;
pt.y = height - it->y * ratio - textSize.height;
}
cv::Point pt = pt1;
pt.x += textSize.width;
pt.y -= textSize.height;
// cv::rectangle(mat, pt1, pt, scalar2, -1);
pt2 = pt1;
pt2.y += textSize.height;
DrawOutlineText(ft2, mat, it->text, pt1, fontScale, scalar, thickness);
DrawOutlineText(ft2, mat, it->text, pt, fontSize, scalar, thickness);
}
vector <int> params;

@ -227,7 +227,7 @@ public class MainActivity extends AppCompatActivity {
}
if (needRequire) {
ActivityCompat.requestPermissions(MainActivity.this, accessPermissions, MY_PERMISSIONS_REQUEST_FOREGROUND_SERVICE);
return;
// return;
}
binding.logs.setText("");

@ -18,9 +18,9 @@ android.nonTransitiveRClass=true
android.useAndroidX=true
android.enableJetifier=true
# opencvsdk=D:/Workspace/deps/opencv-mobile-4.8.0-android
opencvsdk=D:/Workspace/deps/opencv-mobile-4.9.0-android
coreroot=D:/Workspace/Github/xymp/Core
opencvsdk=D:/Workspace/deps/opencv-v5
# opencvsdk=D:/Workspace/deps/opencv-v5
asioroot=D:/Workspace/deps/asio-1.28.0
evpproot=D:/Workspace/Github/evpp
ncnnroot=D:/Workspace/deps/ncnn-20230517-android-vulkan

Loading…
Cancel
Save