You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Cigarette/CigaretteSingle/AlgCommon.cpp

312 lines
8.3 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "AlgCommon.h"
//保护rect边界防止越界访问造成程序崩溃
bool protectRect(cv::Rect& rect, int width, int height)
{
if (width == 0 || height == 0)
{
return false;
}
rect.x = std::max(rect.x, 0);
rect.x = std::min(rect.x, width - 1);
rect.y = std::max(rect.y, 0);
rect.y = std::min(rect.y, height - 1);
int right = rect.x + rect.width;
int bottom = rect.y + rect.height;
right = std::max(right, 0);
right = std::min(right, width - 1);
bottom = std::max(bottom, 0);
bottom = std::min(bottom, height - 1);
rect.width = std::max(right - rect.x, 0);
rect.height = std::max(bottom - rect.y, 0);
if (rect.width == 0 || rect.height == 0)
return false;
return true;
}
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(cv::Mat& dst, const char* str, cv::Point org, cv::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, "\n", bufT);
while (ln != 0)
{
GetStringSize(hDC, ln, &cw, &ch);
strBaseW = std::max(strBaseW, cw);
strBaseH = std::max(strBaseH, ch);
ln = strtok_s(0, "\n", 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, "\n", bufT);
int outTextY = 0;
while (ln != 0)
{
TextOutA(hDC, 0, outTextY, ln, strlen(ln));
outTextY += singleRow;
ln = strtok_s(0, "\n", 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);
}
void putTextCorner(cv::Mat& image, std::string text, cv::Scalar color, int where)
{
//设置绘制文本的相关参数
int x_margin = 25;
int y_margin = 25;
int font_face = cv::FONT_HERSHEY_COMPLEX;
double font_scale = 1.5;
int thickness = 2;
int baseline;
//获取文本框的长宽
cv::Size text_size = cv::getTextSize(text, font_face, font_scale, thickness, &baseline);
//将文本框居中绘制
cv::Point origin;
switch (where)
{
case 1: //左上
origin.x = x_margin;
origin.y = y_margin;
break;
case 2: //右上
origin.x = image.cols - x_margin - text_size.width;
origin.y = y_margin;
break;
case 3: //左下
origin.x = x_margin;
origin.y = image.rows - y_margin;
break;
case 4: //右下
origin.x = image.cols - x_margin - text_size.width;
origin.y = image.rows - y_margin;
break;
default:
origin.x = image.cols / 2 - text_size.width / 2;
origin.y = image.rows / 2 + text_size.height / 2;
break;
}
cv::putText(image, text, origin, font_face, font_scale, color, thickness, 8, false);
}
void fistEROthenDIL(cv::Mat& input,uint8_t EROsize,uint8_t DILsize)
{
cv::Mat element_erode, element_dilate;
if (EROsize)
{
element_erode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(EROsize, EROsize));
cv::erode(input, input, element_erode);
}
if (DILsize)
{
element_dilate = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(DILsize, DILsize));
cv::dilate(input, input, element_dilate);
}
}
void fistDILthenERO(cv::Mat& input, uint8_t DILsize, uint8_t EROsize)
{
cv::Mat element_erode, element_dilate;
if (DILsize)
{
element_dilate = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(DILsize, DILsize));
cv::dilate(input, input, element_dilate);
}
if (EROsize)
{
element_erode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(EROsize, EROsize));
cv::erode(input, input, element_erode);
}
}
bool isInside(cv::Rect rect1, cv::Rect rect2)
{
return (rect1 == (rect1&rect2));
}
cv::Point getCenterPoint(cv::Rect rect)
{
cv::Point cpt;
cpt.x = rect.x + cvRound(rect.width / 2.0);
cpt.y = rect.y + cvRound(rect.height / 2.0);
return cpt;
}
cv::Rect rectCenterScale(cv::Rect rect, cv::Size size)
{
rect = rect + size;
cv::Point pt;
pt.x = cvRound(size.width / 2.0);
pt.y = cvRound(size.height / 2.0);
return (rect - pt);
}
uchar minimum(uchar a, uchar b)
{
return a <= b ? a : b;
}
cv::Mat rgb2cmyk(cv::Mat& rgb)
{
cv::Mat cmyk = cv::Mat::zeros(rgb.rows, rgb.cols, CV_8UC4);
int pixel_num = rgb.rows * rgb.cols;
for (int i = 0; i < pixel_num; i++)
{
uchar c = 255 - rgb.data[3 * i + 0];
uchar m = 255 - rgb.data[3 * i + 1];
uchar y = 255 - rgb.data[3 * i + 2];
uchar K = minimum(minimum(c, m), y);
uchar C = 0;
uchar M = 0;
uchar Y = 0;
if (K == 255)
{
C = 0;
M = 0;
Y = 0;
}
else
{
C = (uchar)((c - K)*255.0 / (255 - K));
M = (uchar)((m - K)*255.0 / (255 - K));
Y = (uchar)((y - K)*255.0 / (255 - K));
}
cmyk.data[4 * i + 0] = C;
cmyk.data[4 * i + 1] = M;
cmyk.data[4 * i + 2] = Y;
cmyk.data[4 * i + 3] = K;
}
return cmyk;
}
bool sort_rect_by_x_center(cv::Rect r1, cv::Rect r2)
{
return (r1.x + r1.width / 2) < (r2.x + r2.width / 2);
}
bool sort_rect_by_y_center(cv::Rect r1, cv::Rect r2)
{
return (r1.y + r1.height / 2) < (r2.y + r2.height / 2);
}
bool sort_rect_by_height(cv::Rect r1, cv::Rect r2)
{
return (r1.height) < (r2.height);
}
bool sort_rect_by_width(cv::Rect r1, cv::Rect r2)
{
return (r1.width) < (r2.width);
}