优化OSD文字描边的实现

serial
BlueMatthew 1 year ago
parent 6ef0f3b652
commit c42c0352ba

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

@ -52,8 +52,12 @@ namespace cv {
@param line_type Line type. See the line for details. @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. @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. /** @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); textSize = ft2->getTextSize(*it, fontSize, thickness, &baseline);
lineHeight = std::max(lineHeight, textSize.height); 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.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); mPhotoInfo.photoTime = time(NULL);
int baseline = 0; int baseline = 0;
cv::Size textSize, textSize2; cv::Size textSize;
double fontScale = 1; // base 1024
double height = mat.size().height; double height = mat.size().height;
double width = mat.size().width; double width = mat.size().width;
// double ratio = std::min(height / 1024, width / 1920); // double ratio = std::min(height / 1024, width / 1920);
double ratio = std::sqrt((height * width) / (1024.0 * 1920.0)); double ratio = height / 1024.0;
fontScale = fontScale * ratio;
// cv::Rect rc(0, 0, mat.cols, mat.rows); // cv::Rect rc(0, 0, mat.cols, mat.rows);
// cv::rectangle (mat, rc, cv::Scalar(255, 255, 255), cv::FILLED); // 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; if (thickness < 2) thickness = 2;
cv::Scalar scalar(255, 255, 255); // white cv::Scalar scalar(255, 255, 255); // white
int fontSize = 24; int fontSize = (int)(24.0 * ratio);
std::string fontPath = m_appPath+ "fonts/Noto.ttf"; 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; cv::Ptr<cv::ft::FreeType2> ft2;
ft2 = cv::ft::createFreeType2(); ft2 = cv::ft::createFreeType2();
ft2->loadFontData(fontPath.c_str(), 0); ft2->loadFontData(fontPath.c_str(), 0);
@ -1040,7 +1050,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
NdkCamera::CAPTURE_RESULT captureResult = mCamera->getCaptureResult(); NdkCamera::CAPTURE_RESULT captureResult = mCamera->getCaptureResult();
char str[128] = { 0 }; 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), (unsigned int)(captureResult.exposureTime / 1000000),
captureResult.sensitibity, captureResult.sensitibity,
captureResult.autoFocus, 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); // 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), ft2->putText(mat, str, cv::Point(0, mat.rows - fontSize - 20),
fontSize, scalarRed, thickness, cv::LINE_AA, false); fontSize, scalarRed, -1, cv::LINE_AA, false);
// text.putText(mat, str.c_str(), cv::Point(0, mat.rows - 20), scalar); // text.putText(mat, str.c_str(), cv::Point(0, mat.rows - 20), scalar);
@ -1062,7 +1072,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
#endif #endif
cv::Point pt1, pt2; cv::Point pt;
for (vector<OSD_INFO>::const_iterator it = mOsds.cbegin(); it != mOsds.cend(); ++it) for (vector<OSD_INFO>::const_iterator it = mOsds.cbegin(); it != mOsds.cend(); ++it)
{ {
if (it->text.empty()) if (it->text.empty())
@ -1070,38 +1080,37 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
continue; continue;
} }
#ifdef _DEBUG
if (it->alignment == OSD_ALIGNMENT_BOTTOM_RIGHT)
{
int aa = 0;
}
#endif
textSize = ft2->getTextSize(it->text, fontSize, thickness, &baseline); 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) if (it->alignment == OSD_ALIGNMENT_TOP_LEFT)
{ {
pt1.x = it->x * ratio; pt.x = it->x * ratio;
pt1.y = it->y * ratio + textSize.height; pt.y = it->y * ratio;
} }
else if (it->alignment == OSD_ALIGNMENT_TOP_RIGHT) else if (it->alignment == OSD_ALIGNMENT_TOP_RIGHT)
{ {
pt1.x = width - textSize.width - it->x * ratio; pt.x = width - textSize.width - it->x * ratio;
pt1.y= it->y * ratio + textSize.height; pt.y= it->y * ratio;
} }
else if (it->alignment == OSD_ALIGNMENT_BOTTOM_RIGHT) else if (it->alignment == OSD_ALIGNMENT_BOTTOM_RIGHT)
{ {
pt1.x = width - textSize.width - it->x * ratio; pt.x = width - textSize.width - it->x * ratio;
pt1.y = height - it->y * ratio; pt.y = height - it->y * ratio - textSize.height;
} }
else if (it->alignment == OSD_ALIGNMENT_BOTTOM_LEFT) else if (it->alignment == OSD_ALIGNMENT_BOTTOM_LEFT)
{ {
pt1.x = it->x * ratio; pt.x = it->x * ratio;
pt1.y = height - it->y * ratio; pt.y = height - it->y * ratio - textSize.height;
} }
DrawOutlineText(ft2, mat, it->text, pt, fontSize, scalar, thickness);
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);
} }
vector <int> params; vector <int> params;

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

@ -18,9 +18,9 @@ android.nonTransitiveRClass=true
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=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 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 asioroot=D:/Workspace/deps/asio-1.28.0
evpproot=D:/Workspace/Github/evpp evpproot=D:/Workspace/Github/evpp
ncnnroot=D:/Workspace/deps/ncnn-20230517-android-vulkan ncnnroot=D:/Workspace/deps/ncnn-20230517-android-vulkan

Loading…
Cancel
Save