You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++/OpenCV中正确绘制波斯语(Farsi)文本?

在OpenCV中绘制波斯语文本的解决方案

问题根源

  • cv::putText仅支持简单拉丁字符,不处理从右到左(RTL)的复杂脚本(如波斯语),也不支持字形连写,因此显示乱码。
  • cv::addText属于OpenCV Contrib模块,VC包管理器默认安装的OpenCV不含该模块,因此抛出未实现异常。
  • 单纯用FreeType实现时,未处理波斯语的RTL排版规则和字形上下文变体(独立/起始/中间/结尾形态),导致字符拆分、顺序反转。

核心解决方案:HarfBuzz + FreeType + OpenCV

HarfBuzz是专业的文本整形库,可处理RTL脚本的排版逻辑、字形连写和上下文变体,配合FreeType渲染字形,最终将结果绘制到OpenCV图像中。

步骤1:安装依赖库

通过vcpkg安装所需库:

vcpkg install freetype harfbuzz opencv4

步骤2:实现代码示例

#include <opencv2/opencv.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <hb.h>
#include <hb-ft.h>

// 绘制RTL文本到OpenCV图像
void drawFarsiText(cv::Mat& img, const std::string& text, const std::string& fontPath, 
                   cv::Point bottomRight, cv::Scalar color, int fontSize) {
    // 初始化FreeType
    FT_Library ftLib;
    FT_Face ftFace;
    if (FT_Init_FreeType(&ftLib) != 0 || FT_New_Face(ftLib, fontPath.c_str(), 0, &ftFace) != 0) {
        return;
    }
    FT_Set_Pixel_Sizes(ftFace, 0, fontSize);

    // 初始化HarfBuzz
    hb_font_t* hbFont = hb_ft_font_create(ftFace, nullptr);
    hb_buffer_t* hbBuffer = hb_buffer_create();
    hb_buffer_add_utf8(hbBuffer, text.c_str(), -1, 0, -1);
    // 设置文本方向:RTL,波斯语脚本
    hb_buffer_set_direction(hbBuffer, HB_DIRECTION_RTL);
    hb_buffer_set_script(hbBuffer, HB_SCRIPT_ARABIC);
    hb_buffer_set_language(hbBuffer, hb_language_from_string("fa", -1));

    // 文本整形:生成排版后的字形信息
    hb_shape(hbFont, hbBuffer, nullptr, 0);
    unsigned int glyphCount;
    hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(hbBuffer, &glyphCount);
    hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(hbBuffer, &glyphCount);

    // 计算文本总宽度(用于确定起始X坐标)
    int totalWidth = 0;
    for (unsigned int i = 0; i < glyphCount; ++i) {
        totalWidth += glyphPositions[i].x_advance >> 6; // HarfBuzz的单位是1/64像素
    }

    int x = bottomRight.x - totalWidth;
    int y = bottomRight.y;

    // 逐个渲染字形到图像
    for (unsigned int i = 0; i < glyphCount; ++i) {
        // 加载字形
        if (FT_Load_Glyph(ftFace, glyphInfos[i].codepoint, FT_LOAD_DEFAULT) != 0) {
            continue;
        }
        FT_Render_Glyph(ftFace->glyph, FT_RENDER_MODE_NORMAL);

        FT_Bitmap& bitmap = ftFace->glyph->bitmap;
        int glyphX = x + (glyphPositions[i].x_offset >> 6);
        int glyphY = y - (glyphPositions[i].y_offset >> 6) - bitmap.rows;

        // 确保字形在图像范围内
        if (glyphX < 0 || glyphY < 0 || glyphX + bitmap.width > img.cols || glyphY + bitmap.rows > img.rows) {
            x += glyphPositions[i].x_advance >> 6;
            continue;
        }

        // 将灰度字形转换为彩色并绘制到图像
        for (int row = 0; row < bitmap.rows; ++row) {
            for (int col = 0; col < bitmap.width; ++col) {
                uchar alpha = bitmap.buffer[row * bitmap.pitch + col];
                if (alpha == 0) continue;
                float alphaNorm = alpha / 255.0f;
                cv::Vec3b& pixel = img.at<cv::Vec3b>(glyphY + row, glyphX + col);
                pixel[0] = cv::saturate_cast<uchar>(pixel[0] * (1 - alphaNorm) + color[0] * alphaNorm);
                pixel[1] = cv::saturate_cast<uchar>(pixel[1] * (1 - alphaNorm) + color[1] * alphaNorm);
                pixel[2] = cv::saturate_cast<uchar>(pixel[2] * (1 - alphaNorm) + color[2] * alphaNorm);
            }
        }

        // 更新X坐标(RTL方向,向左移动)
        x += glyphPositions[i].x_advance >> 6;
    }

    // 释放资源
    hb_buffer_destroy(hbBuffer);
    hb_font_destroy(hbFont);
    FT_Done_Face(ftFace);
    FT_Done_FreeType(ftLib);
}

int main() {
    cv::Mat img = cv::Mat(500, 800, CV_8UC3, cv::Scalar(255, 255, 255));
    std::string farsiText = "سلام دنیا"; // 波斯语"你好世界"
    std::string fontPath = "path/to/your/farsi/font.ttf"; // 替换为波斯语字体路径,比如Vazirmatn.ttf

    drawFarsiText(img, farsiText, fontPath, cv::Point(700, 250), cv::Scalar(0, 0, 0), 48);

    cv::imshow("Farsi Text", img);
    cv::waitKey(0);
    return 0;
}

代码关键说明

  1. HarfBuzz文本整形:设置方向为RTL、脚本为阿拉伯语(波斯语基于阿拉伯脚本),生成正确的字形序列和位置偏移,解决字符顺序和连写问题。
  2. 坐标计算:先计算文本总宽度,从指定的右下角向左偏移起始X坐标,符合RTL排版逻辑。
  3. 字形渲染:FreeType渲染灰度字形后,通过alpha混合将彩色文本绘制到OpenCV图像中。

替代方案

  1. Pango + Cairo:Pango处理文本排版,Cairo渲染到图像后转换为cv::Mat,适合需要更复杂排版(如多行、对齐)的场景。
  2. Qt绘图:使用QPainter在QPixmap上绘制波斯语文本,再将QPixmap转换为cv::Mat,适合Qt项目集成。

内容的提问来源于stack exchange,提问作者Babak.Abad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 16:25:34