193 lines
6.2 KiB
C++
193 lines
6.2 KiB
C++
#pragma once
|
||
#include <opencv.hpp>
|
||
|
||
#pragma region 画叉
|
||
static void Cross(cv::Mat& image, const cv::Point& center, int length, int thickness, const cv::Scalar& color = cv::Scalar(255, 255, 255)) {
|
||
// 检查输入图像是否有效
|
||
if (image.empty()) {
|
||
throw std::invalid_argument("Input image is empty");
|
||
}
|
||
|
||
// 计算水平和垂直线段的起点和终点
|
||
cv::Point horizontalStart(center.x - length / 2, center.y);
|
||
cv::Point horizontalEnd(center.x + length / 2, center.y);
|
||
cv::Point verticalStart(center.x, center.y - length / 2);
|
||
cv::Point verticalEnd(center.x, center.y + length / 2);
|
||
|
||
// 绘制水平和垂直线段
|
||
cv::line(image, horizontalStart, horizontalEnd, color, thickness);
|
||
cv::line(image, verticalStart, verticalEnd, color, thickness);
|
||
}
|
||
#pragma endregion
|
||
|
||
#pragma region 写中文
|
||
static std::wstring utf8ToWstring(const std::string& utf8Str) {
|
||
int len = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0);
|
||
if (len == 0) return L"";
|
||
std::wstring wstr(len, L'\0');
|
||
MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wstr[0], len);
|
||
wstr.pop_back(); // remove null terminator
|
||
return wstr;
|
||
}
|
||
// 在图像上绘制中文(仅 Windows,使用 GDI)
|
||
static void putTextZH(cv::Mat& image, const std::string& text, cv::Point org, int fontSize = 20, cv::Scalar color = cv::Scalar(255, 0, 0)) {
|
||
if (image.channels() != 3)
|
||
throw std::runtime_error("Only supports 3-channel images");
|
||
|
||
// 转为 BGRA
|
||
cv::Mat img;
|
||
cv::cvtColor(image, img, cv::COLOR_BGR2BGRA);
|
||
|
||
HDC hdc = GetDC(nullptr);
|
||
HDC memDC = CreateCompatibleDC(hdc);
|
||
|
||
BITMAPINFO bmi = {};
|
||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
bmi.bmiHeader.biWidth = img.cols;
|
||
bmi.bmiHeader.biHeight = -img.rows;
|
||
bmi.bmiHeader.biPlanes = 1;
|
||
bmi.bmiHeader.biBitCount = 32;
|
||
bmi.bmiHeader.biCompression = BI_RGB;
|
||
|
||
void* pBits = nullptr;
|
||
HBITMAP hBitmap = CreateDIBSection(memDC, &bmi, DIB_RGB_COLORS, &pBits, nullptr, 0);
|
||
SelectObject(memDC, hBitmap);
|
||
memcpy(pBits, img.data, img.total() * img.elemSize());
|
||
|
||
HFONT hFont = CreateFontW(fontSize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
|
||
GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||
ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, L"微软雅黑");
|
||
SelectObject(memDC, hFont);
|
||
|
||
SetBkMode(memDC, TRANSPARENT);
|
||
SetTextColor(memDC, RGB(color[2], color[1], color[0]));
|
||
|
||
TextOutW(memDC, org.x, org.y, utf8ToWstring(text).c_str(), static_cast<int>(utf8ToWstring(text).length()));
|
||
|
||
GetDIBits(memDC, hBitmap, 0, img.rows, img.data, &bmi, DIB_RGB_COLORS);
|
||
|
||
cv::cvtColor(img, image, cv::COLOR_BGRA2BGR);
|
||
|
||
DeleteObject(hFont);
|
||
DeleteObject(hBitmap);
|
||
DeleteDC(memDC);
|
||
ReleaseDC(nullptr, hdc);
|
||
}
|
||
class TextRendererBase {
|
||
public:
|
||
virtual ~TextRendererBase() = default;
|
||
virtual void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) = 0;
|
||
};
|
||
|
||
class TextRendererZH : public TextRendererBase {
|
||
public:
|
||
TextRendererZH(int width, int height, int fontSize = 20, const std::wstring& fontName = L"微软雅黑")
|
||
: width_(width), height_(height), fontSize_(fontSize), fontName_(fontName)
|
||
{
|
||
screenDC_ = GetDC(nullptr);
|
||
createResources();
|
||
}
|
||
|
||
~TextRendererZH() {
|
||
releaseResources();
|
||
if (screenDC_) ReleaseDC(nullptr, screenDC_);
|
||
}
|
||
|
||
void putText(cv::Mat& image, const std::string& text, cv::Point org, cv::Scalar color = cv::Scalar(255, 0, 0)) override {
|
||
if (image.channels() != 3)
|
||
throw std::runtime_error("TextRendererZH only supports 3-channel BGR images.");
|
||
|
||
if (image.cols != width_ || image.rows != height_) {
|
||
resize(image.cols, image.rows);
|
||
}
|
||
|
||
cv::Mat img;
|
||
cv::cvtColor(image, img, cv::COLOR_BGR2BGRA);
|
||
|
||
memcpy(pBits_, img.data, img.total() * img.elemSize());
|
||
|
||
SetBkMode(memDC_, TRANSPARENT);
|
||
SetTextColor(memDC_, RGB(color[2], color[1], color[0]));
|
||
|
||
std::wstring wtext = utf8ToWstring(text);
|
||
TextOutW(memDC_, org.x, org.y, wtext.c_str(), (int)wtext.length());
|
||
|
||
GetDIBits(memDC_, hBitmap_, 0, height_, img.data, &bmi_, DIB_RGB_COLORS);
|
||
|
||
cv::cvtColor(img, image, cv::COLOR_BGRA2BGR);
|
||
}
|
||
|
||
void resize(int width, int height) {
|
||
if (width == width_ && height == height_) return;
|
||
|
||
releaseResources();
|
||
|
||
width_ = width;
|
||
height_ = height;
|
||
createResources();
|
||
}
|
||
|
||
private:
|
||
void createResources() {
|
||
memDC_ = CreateCompatibleDC(screenDC_);
|
||
|
||
memset(&bmi_, 0, sizeof(bmi_));
|
||
bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
bmi_.bmiHeader.biWidth = width_;
|
||
bmi_.bmiHeader.biHeight = -height_;
|
||
bmi_.bmiHeader.biPlanes = 1;
|
||
bmi_.bmiHeader.biBitCount = 32;
|
||
bmi_.bmiHeader.biCompression = BI_RGB;
|
||
|
||
hBitmap_ = CreateDIBSection(memDC_, &bmi_, DIB_RGB_COLORS, &pBits_, nullptr, 0);
|
||
SelectObject(memDC_, hBitmap_);
|
||
|
||
hFont_ = CreateFontW(
|
||
fontSize_, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
|
||
GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||
ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, fontName_.c_str());
|
||
SelectObject(memDC_, hFont_);
|
||
}
|
||
|
||
void releaseResources() {
|
||
if (hFont_) {
|
||
DeleteObject(hFont_);
|
||
hFont_ = nullptr;
|
||
}
|
||
if (hBitmap_) {
|
||
DeleteObject(hBitmap_);
|
||
hBitmap_ = nullptr;
|
||
pBits_ = nullptr;
|
||
}
|
||
if (memDC_) {
|
||
DeleteDC(memDC_);
|
||
memDC_ = nullptr;
|
||
}
|
||
}
|
||
|
||
// UTF8 转宽字符串
|
||
static std::wstring utf8ToWstring(const std::string& str) {
|
||
if (str.empty()) return {};
|
||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
|
||
std::wstring wstrTo(size_needed, 0);
|
||
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstrTo[0], size_needed);
|
||
return wstrTo;
|
||
}
|
||
|
||
private:
|
||
int width_;
|
||
int height_;
|
||
int fontSize_;
|
||
std::wstring fontName_;
|
||
|
||
HDC screenDC_ = nullptr;
|
||
HDC memDC_ = nullptr;
|
||
HBITMAP hBitmap_ = nullptr;
|
||
void* pBits_ = nullptr;
|
||
BITMAPINFO bmi_{};
|
||
|
||
HFONT hFont_ = nullptr;
|
||
};
|
||
#pragma endregion
|
||
|