- 问题
- 解决方案
- 步骤一:生成中文图片
- 步骤二:中文图片蒙皮到视频帧,形成中文显示效果
在jetson nano这样的嵌入式设备上,用opencv拉流,并在实时视频上面,显示汉字。
关于使用opencv/c++显示中文,网上文章分为两种:
- 使用freetype库+cv::putText()函数。该种方法仅适用于windows!
- 使用嵌入式Qt做中文显示。这是嵌入式设备做图形显示的正途,包括展现实时视频等,最好都用Qt做。
本人没有学过qt,因此找到一种取巧的办法,在win上生成中文图片,再将该图片蒙皮到视频帧,形成视频上有中文的效果。
解决方案 步骤一:生成中文图片在windows上打开ppt,创建空白页面,选择“插入”–>“文本框”,选择“横排文本框”,创建一个文本框,里面填入你需要的中文。
将文本框的背景设置为白色,字体设置为红色(后面展示的字体就是红色的)。然后右键文本框,将该文本框保存为hanzi.png图片。
其中,需要注意的是,
- 建议选择较为粗壮的字体,如“华文琥珀”等。
- 框体不宜过大。
我的如图
文本框另存为hanzi.png。
蒙皮简易代码参考博客:《opencv3/C++视频中叠加透明图片的实现》
- 创建测试项目test_rtsp
mkdir ~/test_rtsp cd test_rtsp
将上述文本框图片hanzi.png复制到该项目目录下。
- c++源码
在项目目录test_rtsp下创建 CMakeLists.txt 和 test_rtsp.cpp,
touch CMakeLists.txt touch test_rtsp.cpp
在CMakeLists.txt中添加如下内容:
cmake_minimum_required(VERSION 2.12)
project(DisplayRTSP)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenCV REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
add_executable(test_rtsp test_rtsp.cpp)
target_link_libraries(test_rtsp ${OpenCV_LIBS})
在test_rtsp.cpp中添加如下内容:
// video_test.cpp #include#include #include #include #include #include #include #include #include #include #include #include "time.h" static std::mutex mut; static std::atomic_bool isOpen; using namespace cv; using namespace std; static void frame_get(cv::Mat* pframe, const std::string& adm, const std::string& pwd, const std::string& ip) { cv::VideoCapture capture("rtsp://"+adm+":"+pwd+"@"+ip); if (!capture.isOpened()) { std::cout << "------reconnecting---------" << ip << std::endl; isOpen = false; } cv::Mat frame; while (isOpen) { capture >> frame; if (mut.try_lock()) { frame.copyTo(*pframe); mut.unlock(); } cv::waitKey(5); } capture.release(); } int main(int argc, char* argv[]) { cv::setNumThreads(1); isOpen = true; cv::Mat frame, temp_frame; // 填入摄像头账号,我的为admin std::string adm = "admin"; //填入摄像头密码, std::string pwd = "xxx"; //填入摄像头ip std::string ip = "192.168.20.22"; std::thread t(frame_get, &frame, adm, pwd, ip); //视频窗口设置 cv::namedWindow(ip, cv::WINDOW_NORMAL); //cv::setWindowProperty(ip, cv::WND_PROP_FULLSCREEN, cv::WINDOW_FULLSCREEN); cv::moveWindow(ip, 10, 10); cv::resizeWindow(ip, 1900, 1000); //给显示窗口分配一个线程,确保其正常运行 cv::startWindowThread(); //filename为hanzi.png的绝对路径 std::string filename = "/home/aaeon/work/wangxin/test_rtsp1/hanzi.png"; //cv::Mat png = cv::imread(filename); //以下过程为蒙皮的准备过程,filename为hanzi.png的绝对路径 //imread(filename, 0),其中0为取图片的灰度图 cv::Mat graypng = cv::imread(filename, 0); //cv::threshold中的150为区别hanzi.png中的红色字体和白色背景的阈值;红色的灰度值为255/2.0 //此时graypng中,汉字为黑色,背景为白色 cv::threshold(graypng, graypng, 150, 255, cv::THRESH_BINARY); //此时mask中,汉字为白色,背景为黑色 cv::Mat mask = 255 - graypng; //png为hanzi.png原图 cv::Mat png = cv::imread(filename); cv::Mat imROI; while (isOpen) { mut.lock(); frame.copyTo(temp_frame); mut.unlock(); if (temp_frame.empty()) { continue; } std::cout << "cols: " << temp_frame.cols << ", rows: " << temp_frame.rows << "n"; // 以下两行代码为蒙皮的处理过程 imROI = temp_frame(cv::Rect(100, 100, png.cols, png.rows)); //cv::imshow("imROI", imROI); png.copyTo(imROI, mask); cv::imshow(ip, temp_frame); cv::waitKey(100); if (cv::waitKey(1) == 'q') { break; } } cv::destroyAllWindows(); isOpen = false; t.join(); return 0; } aaeon@aaeon-desktop:~/work/wangxin/test_rtsp1$ vim test_rtsp.cpp if (mut.try_lock()) { frame.copyTo(*pframe); mut.unlock(); } cv::waitKey(5); } capture.release(); }
其中,我做注释的地方,都需要注意下,尤其是涉及摄像头账号、密码、ip等信息,需要你自己填写。
- 编译及运行
在项目目录test_rtsp下,
cd ~/test_rtsp mkdir build cd build cmake .. make ./test_rtsp
效果如下:



