• 为CV::Mat添加中文


    opencv自带的puttext函数,能够很方便地在Mat中添加英文字母。但是在实际项目中,甲方往往希望能够添加中文标识。解决的方法,总的来说有两种,一种是基于基础库的,比如我使用MFC,那么所有的显示最后都是在OnPaint一类的函数中进行处理,这个地方可以使用GDI等技术添加中文;另一类就是基于OpenCV的,也就是在Mat中添加中文。为了实现这个目标,往往需要一些第三方库的支持。比如下图,已经在ImageWatch中能够看到“输出汉字”等中文,而采用的就是基于FreeType的CvxText类。
    关于这些方法,https://www.cnblogs.com/carle-09/  已经进行了很好的整理,我在这里再进行进一步的归纳梳理,方便自己和他人使用。
    一、在图片上打印文字  windows+GDI+TrueType字体
    //====================================================================
    //
    // 文件: textTrueType.h
    //
    // 说明: OpenCV汉字输出
    //
    //====================================================================

    #ifndef PUTTEXT_H_
    #define PUTTEXT_H_

    #include <windows.h>
    #include <string>
    #include <opencv2/opencv.hpp>

    using namespace cv;

    void GetStringSize(HDC hDC, const char* str, int* w, int* h);
    void putTextZH(Mat &dst, const char* str, Point org, Scalar color, int fontSize,
        const char *fn = "Arial", bool italic = false, bool underline = false);

    #endif // PUTTEXT_H_

    //====================================================================
    //
    // 文件: textTrueType.cpp
    //
    // 说明: OpenCV汉字输出
    //
    //====================================================================
    #include "textTrueType.h"

    void GetStringSize(HDC hDC, const char* str, int* w, int* h)
    {
        SIZE size;
        GetTextExtentPoint32A(hDC, str, strlen(str), &size);
        if (w != 0) *w = size.cx;
        if (h != 0) *h = size.cy;
    }

    void putTextZH(Mat &dst, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline)
    {
        CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));

        int x, y, r, b;
        if (org.x > dst.cols || org.y > dst.rows) return;
        x = org.x < 0 ? -org.x : 0;
        y = org.y < 0 ? -org.y : 0;

        LOGFONTA lf;
        lf.lfHeight = -fontSize;
        lf.lfWidth = 0;
        lf.lfEscapement = 0;
        lf.lfOrientation = 0;
        lf.lfWeight = 5;
        lf.lfItalic = italic;   //斜体
        lf.lfUnderline = underline; //下划线
        lf.lfStrikeOut = 0;
        lf.lfCharSet = DEFAULT_CHARSET;
        lf.lfOutPrecision = 0;
        lf.lfClipPrecision = 0;
        lf.lfQuality = PROOF_QUALITY;
        lf.lfPitchAndFamily = 0;
        strcpy_s(lf.lfFaceName, fn);

        HFONT hf = CreateFontIndirectA(&lf);
        HDC hDC = CreateCompatibleDC(0);
        HFONT hOldFont = (HFONT)SelectObject(hDC, hf);

        int strBaseW = 0, strBaseH = 0;
        int singleRow = 0;
        char buf[1 << 12];
        strcpy_s(buf, str);
        char *bufT[1 << 12];  // 这个用于分隔字符串后剩余的字符,可能会超出。
        //处理多行
        {
            int nnh = 0;
            int cw, ch;

            const char* ln = strtok_s(buf, " ",bufT);
            while (ln != 0)
            {
                GetStringSize(hDC, ln, &cw, &ch);
                strBaseW = max(strBaseW, cw);
                strBaseH = max(strBaseH, ch);

                ln = strtok_s(0, " ",bufT);
                nnh++;
            }
            singleRow = strBaseH;
            strBaseH *= nnh;
        }

        if (org.x + strBaseW < 0 || org.y + strBaseH < 0)
        {
            SelectObject(hDC, hOldFont);
            DeleteObject(hf);
            DeleteObject(hDC);
            return;
        }

        r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
        b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
        org.x = org.x < 0 ? 0 : org.x;
        org.y = org.y < 0 ? 0 : org.y;

        BITMAPINFO bmp = { 0 };
        BITMAPINFOHEADER& bih = bmp.bmiHeader;
        int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4));

        bih.biSize = sizeof(BITMAPINFOHEADER);
        bih.biWidth = strBaseW;
        bih.biHeight = strBaseH;
        bih.biPlanes = 1;
        bih.biBitCount = 24;
        bih.biCompression = BI_RGB;
        bih.biSizeImage = strBaseH * strDrawLineStep;
        bih.biClrUsed = 0;
        bih.biClrImportant = 0;

        void* pDibData = 0;
        HBITMAP hBmp = CreateDIBSection(hDC, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0);

        CV_Assert(pDibData != 0);
        HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp);

        //color.val[2], color.val[1], color.val[0]
        SetTextColor(hDC, RGB(255, 255, 255));
        SetBkColor(hDC, 0);
        //SetStretchBltMode(hDC, COLORONCOLOR);

        strcpy_s(buf, str);
        const char* ln = strtok_s(buf, " ",bufT);
        int outTextY = 0;
        while (ln != 0)
        {
            TextOutA(hDC, 0, outTextY, ln, strlen(ln));
            outTextY += singleRow;
            ln = strtok_s(0, " ",bufT);
        }
        uchar* dstData = (uchar*)dst.data;
        int dstStep = dst.step / sizeof(dstData[0]);
        unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep;
        unsigned char* pStr = (unsigned char*)pDibData + x * 3;
        for (int tty = y; tty <= b; ++tty)
        {
            unsigned char* subImg = pImg + (tty - y) * dstStep;
            unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep;
            for (int ttx = x; ttx <= r; ++ttx)
            {
                for (int n = 0; n < dst.channels(); ++n){
                    double vtxt = subStr[n] / 255.0;
                    int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n];
                    subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv);
                }

                subStr += 3;
                subImg += dst.channels();
            }
        }

        SelectObject(hDC, hOldBmp);
        SelectObject(hDC, hOldFont);
        DeleteObject(hf);
        DeleteObject(hBmp);
        DeleteDC(hDC);
    }

    //====================================================================
    //
    // 文件: test_main.cpp
    //
    // 说明: OpenCV汉字输出,测试主函数
    //
    //====================================================================
    #include "opencv2/opencv.hpp"
    #include "textTrueType.h"

    using namespace std;
    using namespace cv;

    void main()
    {
        //Mat img(150,600,CV_8UC3,Scalar(255,255,255));//初始化图像
        Mat img = imread("D:\005_test_4\testImg\road_6.png");
        putTextZH(img, "打印汉字,汉字,汉字!", Point(30, 30), Scalar(255, 0, 0), 45, "华文行楷");
        imwrite("1.png", img);
        imshow("", img);
        waitKey(0);
    }

    二、在图片上打印文字 FreeType库
    //====================================================================
    //====================================================================
    //
    // 文件: CvxText.h
    //
    // 说明: OpenCV汉字输出
    //
    //====================================================================
    //====================================================================
    #ifndef OPENCV_CVX_TEXT_2007_08_31_H
    #define OPENCV_CVX_TEXT_2007_08_31_H
    /**
    * file CvxText.h
    * rief OpenCV汉字输出接口
    *
    * 实现了汉字输出功能。
    */

    #include <ft2build.h>
    #include FT_FREETYPE_H
    #include <opencv2opencv.hpp>
    //modified
    //将CvxText.h中的#include<cv.h> #include <highgui.h>用#include<opnecv2/opencv.hpp>替代;
    /**
    * class CvxText
    * rief OpenCV中输出汉字
    *
    * OpenCV中输出汉字。字库提取采用了开源的FreeFype库。由于FreeFype是
    * GPL版权发布的库,和OpenCV版权并不一致,因此目前还没有合并到OpenCV
    * 扩展库中。
    *
    * 显示汉字的时候需要一个汉字字库文件,字库文件系统一般都自带了。
    * 这里采用的是一个开源的字库:“文泉驿正黑体”。
    *
    * 关于"OpenCV扩展库"的细节请访问
    * http://code.google.com/p/opencv-extension-library/
    *
    * 关于FreeType的细节请访问
    * http://www.freetype.org/
    *
    * 例子:
    *
    * code
    int main(int argc, char *argv[])
    {
       // 定义CvxApplication对象
       CvxApplication app(argc, argv);
       // 打开一个影象
       IplImage *img = cvLoadImage("test.jpg", 1);
       // 输出汉字
       {
          // "wqy-zenhei.ttf"为文泉驿正黑体
          CvText text("wqy-zenhei.ttf");
          const char *msg = "在OpenCV中输出汉字!";
          float p = 0.5;
          text.setFont(NULL, NULL, NULL, &p);   // 透明处理
          text.putText(img, msg, cvPoint(100, 150), CV_RGB(255,0,0));
       }
       // 定义窗口,并显示影象
       CvxWindow myWin("myWin");
       myWin.showImage(img);
       // 进入消息循环
       return app.exec();
    }
    * endcode
    */

    class CvxText  
    {
       // 禁止copy
       CvxText& operator=(const CvxText&);
       //================================================================
       //================================================================
    public:
       /**
        * 装载字库文件
        */

       CvxText(const char *freeType);
       virtual ~CvxText();
       //================================================================
       //================================================================
       /**
        * 获取字体。目前有些参数尚不支持。
        *
        * param font        字体类型, 目前不支持
        * param size        字体大小/空白比例/间隔比例/旋转角度
        * param underline   下画线
        * param diaphaneity 透明度
        *
        * sa setFont, restoreFont
        */

       void getFont(int *type,
          CvScalar *size=NULL, bool *underline=NULL, float *diaphaneity=NULL);
       /**
        * 设置字体。目前有些参数尚不支持。
        *
        * param font        字体类型, 目前不支持
        * param size        字体大小/空白比例/间隔比例/旋转角度
        * param underline   下画线
        * param diaphaneity 透明度
        *
        * sa getFont, restoreFont
        */

       void setFont(int *type,
          CvScalar *size=NULL, bool *underline=NULL, float *diaphaneity=NULL);
       /**
        * 恢复原始的字体设置。
        *
        * sa getFont, setFont
        */

       void restoreFont();
       //================================================================
       //================================================================
       /**
        * 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。
        *
        * param img  输出的影象
        * param text 文本内容
        * param pos  文本位置
        *
        * eturn 返回成功输出的字符长度,失败返回-1。
        */

       int putText(IplImage *img, const char    *text, CvPoint pos);
       /**
        * 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。
        *
        * param img  输出的影象
        * param text 文本内容
        * param pos  文本位置
        *
        * eturn 返回成功输出的字符长度,失败返回-1。
        */

       int putText(IplImage *img, const wchar_t *text, CvPoint pos);
       /**
        * 输出汉字。遇到不能输出的字符将停止。
        *
        * param img   输出的影象
        * param text  文本内容
        * param pos   文本位置
        * param color 文本颜色
        *
        * eturn 返回成功输出的字符长度,失败返回-1。
        */

       int putText(IplImage *img, const char    *text, CvPoint pos, CvScalar color);
       /**
        * 输出汉字。遇到不能输出的字符将停止。
        *
        * param img   输出的影象
        * param text  文本内容
        * param pos   文本位置
        * param color 文本颜色
        *
        * eturn 返回成功输出的字符长度,失败返回-1。
        */

       int putText(IplImage *img, const wchar_t *text, CvPoint pos, CvScalar color);
       //================================================================
       //================================================================
    private:
       // 输出当前字符, 更新m_pos位置
       void putWChar(IplImage *img, wchar_t wc, CvPoint &pos, CvScalar color);
       //================================================================
       //================================================================
    private:
       FT_Library   m_library;   // 字库
       FT_Face      m_face;      // 字体
       //================================================================
       //================================================================
       // 默认的字体输出参数
       int         m_fontType;
       CvScalar   m_fontSize;
       bool      m_fontUnderline;
       float      m_fontDiaphaneity;
       //================================================================
       //================================================================
    };

    #endif // OPENCV_CVX_TEXT_2007_08_31_H

    //====================================================================
    //====================================================================
    //
    // 文件: text_in_image.cpp
    //
    // 说明: OpenCV汉字输出
    //
    //====================================================================
    //====================================================================
    #include <iostream>
    #include "opencv2/opencv.hpp"
    #include"CvxText.h"

    using namespace std;
    using namespace cv;
    //--------------------------------IPLImage格式的图像, 使用FreeType库---------------------------------------
    int main(int argc, char *argv[])
    {
        IplImage *img = cvLoadImage("D:\005_test_4\testImg\road_6.png");
        {
            CvxText text("simfang.ttf"); 
            const char *msg = "汉字!汉字!汉字!";
            float p = 1.5;
            text.setFont(NULL, NULL, NULL, &p); 
            text.putText(img, msg, cvPoint(100, 150), CV_RGB(0,255,0));
        }
        cvShowImage("test", img ); cvWaitKey(-1);
        cvReleaseImage(&img);
        return 0;
    }

    三、在图片上打印文字 putText()
    /*
    作者:WP @20190626
    功能:opencv在图片中写入文字
    说明:
        (1)只在图像上打印 数字、字母的话:
                1.Mat格式的图像,可以使用opencv自带的putText。
                2.IPLImage格式的图像,可以使用自带的cvInitFont和cvPutText函数。
        (2)在图像上打印 汉字的话,可以使用FreeType库。
                FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件。
    */

    #include <iostream>
    #include "opencv2/opencv.hpp"

    using namespace std;
    using namespace cv;

    //--------------------------------Mat格式的图像,可以使用opencv自带的putText()函数---------------------------------------
    int main( )
    {
        //Mat image = Mat::zeros(Size(640, 480), CV_8UC3);            // 创建空白图用于绘制文字
        //image.setTo(Scalar(100, 0, 0));        //设置蓝色背景
        Mat image = imread("D:\005_test_4\testImg\road_6.png",1);    // 最后显示,1---原图,0---灰度图

        //设置绘制文本的相关参数
        string text = "JILIN UNIVERSITY";
        int font_face = FONT_HERSHEY_COMPLEX; 
        double font_scale = 2;
        int thickness = 2;
        int baseline;
        //获取文本框的长宽
        Size text_size = getTextSize(text, font_face, font_scale, thickness, &baseline);

        //将文本框居中绘制
        Point origin; 
        origin.x = image.cols / 2 - text_size.width / 2;
        origin.y = image.rows / 2 + text_size.height / 2;
        putText(image, text, origin, font_face, font_scale, Scalar(0, 255, 255), thickness, 8, 0);
        putText(image, "This image is clear.", Point(50, 100), FONT_HERSHEY_SIMPLEX, 1, Scalar(0,0,255), 4, 8);

        //显示绘制结果
        imshow("image", image);
        waitKey(0);
        return 0;
    }

    小结:第一种方法,基于现有的环境,一个函数解决“中文书写”问题,简单直接;但是其它方法 也需要了解掌握,以方便应对不同的情况和要求。
    P.S方法1使用过程中,容易出现的错误和解决方法:来源: <https://www.cnblogs.com/rainbow70626/p/9073017.html>

    std::max、std::min error C2589: “(”:“::”右边的非法标记,error C2059: 语法错误:“::”

      在VC++种同时包含头文件#include <windows.h>和#include <algorithm>后就会出现无法正常使用std标准库中的min和max模板函数,经过查阅发现这是因为在Windows.h种也有min和max的定义,这样就导致了algorithm中的min和max无法正常使用,这里给出两种解决方案,来解决std命名空间无法使用min和max的问题。

    解决方案一

    使用std::min或者std::max的时候加上括号,避免与Windows.h中的min、max宏定义冲突。

    #include <windows.h>#include <algorithm>(std::min)(100,2000
    );
    (std::max)(
    10,500);

    解决方案二

    禁用Windows.h中的min、max宏定义。

    在Windows.h中可以查阅到min、max的定义为:

    复制代码
    #ifndef NOMINMAX
     
    #ifndef max
    #define max(a,b)            (((a) > (b)) ? (a) : (b))#endif
     
    #ifndef min
    #define min(a,b)            (((a) < (b)) ? (a) : (b))#endif #endif  /* NOMINMAX */
    复制代码

    看懂了定义就很简单了,在包含Windows.h文件之前直接定义一个NOMINMAX宏定义就OK了,如下代码所示:

    #define NOMINMAX#include <windows.h>#include <algorithm>std::max(100, 200);

    解决方案三:

    这个解决办法与第二个本质是一样的。具体方法为:打开工程属性->C/C++->预处理器->预处理器定义->加入NOMINMAX

    OK,经过上面的操作,min,max操作已经正常了。



     




    附件列表

    • 相关阅读:
      openssl用法详解
      单例模式
      __new__静态方法
      django自带加密模块的使用
      celery 框架
      理解RESTful架构
      [Swoole] 在Ubuntu下安装、快速开始
      [Javascript] 动态隐藏和显示 Layui 数据表格的列
      [PHP] CURL获取cookie,模拟登录获取数据
      [Python] 命令行模式阅读博客园的博文
    • 原文地址:https://www.cnblogs.com/jsxyhelu/p/13834246.html
    Copyright © 2020-2023  润新知