OpenCV中cv::putText不支持中日文字符叠加图片,求可行解决方案
OpenCV cv::putText显示中文/日文的解决办法
OpenCV自带的cv::putText仅支持ASCII字符,无法正确渲染中文、日文等Unicode字符,会出现??????这类乱码。以下是几种可行的解决办法:
方案1:使用FreeType库实现Unicode文本渲染
通过FreeType库加载系统中的中文字体(如SimSun、Noto Sans CJK SC等),自定义文本渲染逻辑,直接将Unicode字符绘制到OpenCV图像上。
实现步骤与代码示例
- 确保项目链接FreeType库(需提前安装FreeType开发包)
- 编写自定义渲染函数:
#include <opencv2/opencv.hpp> #include <ft2build.h> #include FT_FREETYPE_H void putTextUnicode(cv::Mat& img, const std::wstring& text, cv::Point pos, const std::string& fontPath, double fontSize, cv::Scalar color) { FT_Library ft; if (FT_Init_FreeType(&ft)) { std::cerr << "FreeType初始化失败" << std::endl; return; } FT_Face face; if (FT_New_Face(ft, fontPath.c_str(), 0, &face)) { std::cerr << "加载字体文件失败,请检查路径是否正确" << std::endl; FT_Done_FreeType(ft); return; } // 设置字体像素大小,数值需根据fontSize调整 FT_Set_Pixel_Sizes(face, 0, static_cast<int>(fontSize * 20)); int currX = pos.x; int currY = pos.y; for (const wchar_t c : text) { if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { std::cerr << "字符渲染失败: " << c << std::endl; continue; } FT_GlyphSlot slot = face->glyph; // 将FreeType生成的灰度位图转为OpenCV Mat cv::Mat glyphMat(cv::Size(slot->bitmap.width, slot->bitmap.rows), CV_8UC1, slot->bitmap.buffer); // 调整绘制位置(FreeType原点在字符左下角,OpenCV在图像左上角) cv::Point glyphPos(currX, currY - slot->bitmap_top); // 检查是否超出图像边界 if (glyphPos.y < 0 || glyphPos.y + glyphMat.rows > img.rows || glyphPos.x < 0 || glyphPos.x + glyphMat.cols > img.cols) { currX += slot->advance.x >> 6; // 移动到下一个字符位置(单位:1/64像素) continue; } // 将灰度位图叠加到彩色图像上,保留透明度 for (int i = 0; i < glyphMat.rows; ++i) { for (int j = 0; j < glyphMat.cols; ++j) { uchar alpha = glyphMat.at<uchar>(i, j); if (alpha > 0) { img.at<cv::Vec3b>(glyphPos.y + i, glyphPos.x + j) = cv::Vec3b(color[0], color[1], color[2]); } } } currX += slot->advance.x >> 6; } FT_Done_Face(face); FT_Done_FreeType(ft); } // 使用示例 int main() { cv::Mat img = cv::Mat::zeros(400, 600, CV_8UC3); // 宽字符串存储Unicode文本 std::wstring text = L"你好世界 こんにちは"; // 替换为你的系统字体路径(Windows下通常为C:/Windows/Fonts/simsun.ttc) putTextUnicode(img, text, cv::Point(20, 200), "simsun.ttc", 1.5, cv::Scalar(118, 185, 0)); cv::imshow("Unicode Text Render", img); cv::waitKey(0); return 0; }
方案2:借助Qt框架完成文本渲染
如果项目已集成Qt,可以将OpenCV的Mat转换为Qt的QImage,利用QPainter的成熟文本渲染能力绘制Unicode字符,再转回Mat格式。
代码示例
#include <opencv2/opencv.hpp> #include <QImage> #include <QPainter> #include <QFont> cv::Mat putTextWithQt(cv::Mat& srcImg, const QString& text, cv::Point pos, const QString& fontName, double fontSize, cv::Scalar color) { // 将OpenCV BGR格式转为Qt的BGR888格式 QImage qImg(srcImg.data, srcImg.cols, srcImg.rows, srcImg.step, QImage::Format_BGR888); QPainter painter(&qImg); // 设置字体参数 QFont font(fontName); font.setPointSizeF(fontSize * 12); painter.setFont(font); painter.setPen(QColor(color[0], color[1], color[2])); // 绘制文本(Qt的drawText原点在字符基线,需注意位置调整) painter.drawText(pos.x, pos.y, text); // 将QImage转回OpenCV Mat cv::Mat result(srcImg.rows, srcImg.cols, CV_8UC3, qImg.bits(), qImg.bytesPerLine()); return result.clone(); } // 使用示例 int main() { cv::Mat img = cv::Mat::zeros(400, 600, CV_8UC3); QString text = "你好世界 こんにちは"; cv::Mat imgWithText = putTextWithQt(img, text, cv::Point(20, 200), "SimSun", 1.5, cv::Scalar(118, 185, 0)); cv::imshow("Qt Text Render", imgWithText); cv::waitKey(0); return 0; }
方案3:预渲染文本为图像再叠加
对于固定文本场景,可先用第三方工具(如系统绘图软件)将需要显示的中文/日文保存为图像,再通过OpenCV的cv::imread读取图像,用cv::copyTo或cv::addWeighted叠加到目标图像上。这种方式无需额外依赖库,但灵活性较低,仅适合文本固定的场景。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

