#include "stdafx.h" #include "MicroImage.h" using namespace cv; using namespace std; MicroImage::MicroImage() : m_width(0) , m_height(0) , m_OriginData(nullptr) , m_CalData(nullptr) , m_ImgName("") , m_DistanceX(0.f) , m_DistanceY(0.f) , m_knowLength(0) , m_TotalSize(0){ m_image.release(); } MicroImage::~MicroImage() { if(m_OriginData) delete m_OriginData; if(m_CalData) delete m_CalData; m_image.release(); } std::string MicroImage::GetStrTime() { char buffer[50]; SYSTEMTIME snow; GetLocalTime(&snow); sprintf_s(buffer, sizeof(buffer), u8"%02d%02d%02d%02d%02d%03d", snow.wMonth, snow.wDay, snow.wHour, snow.wMinute, snow.wSecond, snow.wMilliseconds); return string(buffer); } void MicroImage::Init(const BITMAP& bmp) { m_height = bmp.bmHeight; m_width = bmp.bmWidth; m_Radio = m_width / m_height; m_TotalSize = ((bmp.bmWidth * bmp.bmBitsPixel + 31) / 32) * 4 * bmp.bmHeight * bmp.bmPlanes; m_OriginData = new uchar[m_TotalSize]; m_ImgName = u8"抓图" + GetStrTime(); memcpy_s(m_OriginData, m_TotalSize, bmp.bmBits, m_TotalSize); //m_image = cv::Mat(m_height, m_width, CV_8UC3, m_OriginData); //cv::imwrite(m_ImgName, m_image); } void MicroImage::CropByBorder(int yBegin, int yEnd, int xBegin, int xEnd) { for (int y = yBegin; y <= yEnd; ++y) { for (int x = xBegin; x <= xEnd; ++x) { auto& pc = m_image.at(y, x); if (pc[0] != 0 || pc[1] != 0 || pc[2] != 0) { pc[0] = 0; pc[1] = 0; pc[2] = 0; } } } } void MicroImage::StatisticsBGColor() { Rect cropRect1(m_width / 2 - 40, m_height / 2 - 40, 80, 80); // 中心位置 cropRect1 &= Rect(0, 0, m_width, m_height); // 检查ROI是否在图像范围内 Mat cropMat1 = m_image(cropRect1); Rect cropRect2(0, m_height / 2 - 25, 50, 50); //中左位置 cropRect2 &= Rect(0, 0, m_width, m_height); Mat cropMat2 = m_image(cropRect2); Rect cropRect3(m_width - 25, m_height / 2 - 25, 50, 50); //中右位置 cropRect3 &= Rect(0, 0, m_width, m_height); Mat cropMat3 = m_image(cropRect3); Rect cropRect4(0, 0, 25, 25); //左上角位置 cropRect4 &= Rect(0, 0, m_width, m_height); Mat cropMat4 = m_image(cropRect4); StatisticsRGB(cropMat1); StatisticsRGB(cropMat2); StatisticsRGB(cropMat3); StatisticsRGB(cropMat4); printf("rgb size:%zd\n", m_RgbSet.size()); } void MicroImage::StatisticsRGB(cv::Mat& cropMat) { for (int y = 0; y < cropMat.rows; ++y) { for (int x = 0; x < cropMat.cols; ++x) { Vec3b pixel = cropMat.at(y, x); int r = pixel[2]; // Red int g = pixel[1]; // Green int b = pixel[0]; // Blue //RGB 每个值范围[-2,1],趋近0,偏黑 for (int i = -2; i <= 1; ++i) { for (int j = -2; j <= 1; ++j) { for (int k = -2; k <= 1; ++k) { int rr = max(r + i, 0), gg = max(g + j, 0), bb = max(b + k, 0); rr = min(r + i, 255), gg = min(g + j, 255), bb = min(b + k, 255); m_RgbSet.insert((rr << 16) | (gg << 8) | (bb)); } } } } } } void MicroImage::DrawRedLine(int length, int x, int y) { int centerx = m_width / 2, centery = m_height / 2; if (x == centerx) { //画水平线 for (int xx = centerx - length / 2; xx < centerx + length / 2; ++xx) { //设置红色 auto& pixel = m_image.at(y, xx); pixel[0] = 0; pixel[1] = 0; pixel[2] = 255; } } else { //画垂直线 for (int yy = centery - length / 2; yy < centery + length / 2; ++yy) { //设置红色 auto& pixel = m_image.at(yy, x); pixel[0] = 0; pixel[1] = 0; pixel[2] = 255; } } } bool MicroImage::IslandCheck(int y, int x, std::set& tempSet) { tempSet.insert((y << 16) | x); queue que; que.push((y << 16) | x); while (!que.empty()) { x = que.front() & 0xffff; y = (que.front() >> 16) & 0xffff; que.pop(); int val = (y << 16) + x + 1; //right int colorVal = 0; if (tempSet.find(val) == tempSet.end() && x + 1 < m_width) { auto& right = m_image.at(y, x + 1); if (right[0] != 0 || right[1] != 0 || right[2] != 0) { //不是黑色判断 tempSet.insert(val); que.push(val); } } val = ((y + 1) << 16) + x; //down if (tempSet.find(val) == tempSet.end() && y + 1 < m_height) { auto& down = m_image.at(y + 1, x); if (down[0] != 0 || down[1] != 0 || down[2] != 0) { //不是黑色判断 tempSet.insert(val); que.push(val); } } val = (y << 16) + x - 1; //left if (tempSet.find(val) == tempSet.end() && x - 1 >= 0) { auto& left = m_image.at(y, x - 1); if (left[0] != 0 || left[1] != 0 || left[2] != 0) { //不是黑色判断 tempSet.insert(val); que.push(val); } } val = ((y - 1) << 16) | x; //up if (tempSet.find(val) == tempSet.end() && y - 1 >= 0) { auto& up = m_image.at(y - 1, x); if (up[0] != 0 || up[1] != 0 || up[2] != 0) { //不是黑色判断 tempSet.insert(val); que.push(val); } } if (tempSet.size() > 400) break; } if (que.empty()) //判断是孤岛噪点 return true; return false; } void MicroImage::SquareRemove() { for (int z = 50; z >= 5; z -= 5) { //步长 int x = 0; int y = 0; while (x < m_width && y < m_height) { int allNum = 0, okNum = 0; vector vec; for (int i = y; i < m_height && i < y + z; ++i) { //计算边长z的方形,判断是否要变黑 for (int j = x; j < m_width && j < x + z; ++j) { auto pc = m_image.at(i, j); int val = (pc[2] << 16) | (pc[1] << 8) | pc[0]; if ((pc[0] == 0 && pc[1] == 0 && pc[2] == 0) || m_RgbSet.find(val) != m_RgbSet.end()) { //判断是黑色或者背景色 ++okNum; } ++allNum; vec.emplace_back(Point{ i,j }); } } if (okNum * 1.0f / allNum >= 0.86f) { //背景像素占85%,全部置为黑色 for (auto& it : vec) { auto& pc = m_image.at(it.x, it.y); pc[2] = 0; pc[1] = 0; pc[0] = 0; } } if (x + z < m_width) x += z; else { y += z; x = 0; } } } //if (g_debug) { // cv::imshow("result", m_image); // cv::waitKey(0); //} } bool MicroImage::IsBlack(int y, int x) { if (x < 0 || x >= m_width || y < 0 || y >= m_height) return true; auto pc = m_image.at(y, x); if ((pc[0] != 0 || pc[1] != 0 || pc[2] != 0)) { //非黑色 return false; } return true; } void MicroImage::IsLandRemove() { set tempSet; set candiSet; //可能是孤岛噪点的位置 for (int y = 0; y < m_height; ++y) { candiSet.clear(); int preLastBlack = -1; for (int x = 0; x <= m_width; ++x) { if (IsBlack(y, x) && !IsBlack(y, x - 1) && x - 1 - preLastBlack <= 40) { candiSet.insert(x); } if (!IsBlack(y, x) && IsBlack(y, x - 1)) { preLastBlack = x - 1; } } for (auto x = candiSet.begin(); x != candiSet.end(); ++x) { tempSet.clear(); if (IslandCheck(y, *x, tempSet)) { //是孤岛噪点 for (auto start = tempSet.begin(); start != tempSet.end(); ++start) { Vec3b& pixel = m_image.at(((*start) >> 16) & 0xffff, (*start) & 0xffff); pixel[2] = 0; pixel[1] = 0; pixel[0] = 0; } } } } //if (g_debug) { // cv::imshow("result", m_image); // cv::waitKey(0); //} } void MicroImage::CalBorderCrop(int& dx, int& dy) { //中心点发出一条线,向边缘平推 int centerx = m_width / 2, centery = m_height / 2; int bNum = 0; int lineLen = 250; int j = centery; int upDown = 0, upUp = 0; while (j >= 0) { bNum = 0; for (int i = centerx - lineLen / 2; i < centerx + lineLen / 2; ++i) { auto pixel = m_image.at(j, i); if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) { //判断是黑色 ++bNum; } } if (bNum * 1.f / lineLen <= 0.3f) { //算边界 if (upDown == 0) upDown = j; //矩形的下边 else { upUp = j; //矩形的上边 } } else { if (upDown && upUp && bNum * 1.f >= lineLen * 0.95f) break; } if (bNum == lineLen) j -= 3; else --j; } DrawRedLine(lineLen, centerx, upDown); DrawRedLine(lineLen, centerx, upUp); printf("upDown:%d,upUp:%d\n", upDown, upUp); j = centery; int downDown = 0, downUp = 0; while (j < m_height) { bNum = 0; for (int i = centerx - lineLen / 2; i < centerx + lineLen / 2; ++i) { auto pixel = m_image.at(j, i); if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) { //判断是黑色 ++bNum; } } if (bNum * 1.f / lineLen <= 0.3f) { //算边界 if (downUp == 0) downUp = j; //矩形的下边 else { downDown = j; //矩形的上边 } } else { if (downDown && downUp && bNum * 1.f >= lineLen * 0.95f) break; } if (bNum == lineLen) j += 3; else ++j; } DrawRedLine(lineLen, centerx, downDown); DrawRedLine(lineLen, centerx, downUp); printf("downDown:%d,downUp:%d\n", downDown, downUp); int i = centerx; int leftLeft = 0, leftRight = 0; while (i >= 0) { bNum = 0; for (int y = centery - lineLen / 2; y < centery + lineLen / 2; ++y) { auto pixel = m_image.at(y, i); if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) { //判断是黑色 ++bNum; } } if (bNum * 1.f / lineLen <= 0.3f) { //算边界 if (leftRight == 0) leftRight = i; //矩形的下边 else { leftLeft = i; //矩形的上边 } } else { if (leftRight && leftLeft && bNum * 1.f >= lineLen * 0.95f) break; } if (bNum == lineLen) i -= 3; else --i; } DrawRedLine(lineLen, leftRight, centery); DrawRedLine(lineLen, leftLeft, centery); printf("leftLeft:%d,leftRight:%d\n", leftLeft, leftRight); i = centerx; int rightLeft = 0, rightRight = 0; while (i < m_width) { bNum = 0; for (int y = centery - lineLen / 2; y < centery + lineLen / 2; ++y) { auto pixel = m_image.at(y, i); if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) { //判断是黑色 ++bNum; } } if (bNum * 1.f / lineLen <= 0.3f) { //算边界 if (rightLeft == 0) rightLeft = i; //矩形的下边 else { rightRight = i; //矩形的上边 } } else { if (rightLeft && rightRight && bNum * 1.f >= lineLen * 0.95f) break; } if (bNum == lineLen) i += 3; else ++i; } DrawRedLine(lineLen, rightLeft, centery); DrawRedLine(lineLen, rightRight, centery); printf("rightLeft:%d,rightRight:%d\n", rightLeft, rightRight); CropByBorder(upDown + 1, downUp - 1, 0, leftLeft - 1); CropByBorder(upDown + 1, downUp - 1, leftRight + 1, rightLeft - 1); CropByBorder(upDown + 1, downUp - 1, rightRight + 1, m_width - 1); CropByBorder(0, upUp - 1, 0, leftLeft - 1); CropByBorder(0, upUp - 1, leftRight + 1, rightLeft - 1); CropByBorder(0, upUp - 1, rightRight + 1, m_width - 1); CropByBorder(downDown + 1, m_height - 1, 0, leftLeft - 1); CropByBorder(downDown + 1, m_height - 1, leftRight + 1, rightLeft - 1); CropByBorder(downDown + 1, m_height - 1, rightRight + 1, m_width - 1); //if (g_debug) { // cv::imshow("result", m_image); // cv::waitKey(0); //} //cv::imwrite("11.png", m_image); dy = downUp - upUp; dx = rightLeft - leftLeft; } void MicroImage::CalDistance() { m_image.release(); m_image = cv::Mat(m_height, m_width, CV_8UC3, m_OriginData).clone(); //cv::imwrite(m_ImgName, m_image); //StandardLineDetect(); //标准线段检测 先固定值 StatisticsBGColor(); SquareRemove(); //#if 0 // IsLandRemove(); // Binarization(); // //#endif int dx = 0, dy = 0; CalBorderCrop(dx, dy); m_knowLength = 148; //先固定 m_DistanceY = 0.2 * dy / m_knowLength; m_DistanceX = 0.2 * dx / m_knowLength; m_CalData = new uchar[m_TotalSize]{0}; memcpy_s(m_CalData, m_TotalSize,m_image.data,m_TotalSize); m_image.release(); } void MicroImage::StandardLineDetect() { int cropH = 250; //裁剪高 int cropW = 300; //裁剪宽 Rect cropRect(0, m_height - cropH, cropW, cropH); // 定义感兴趣的区域的矩形框 cropRect &= Rect(0, 0, m_width, m_height); // 检查ROI是否在图像范围内 Mat cropMat = m_image(cropRect); //if (g_isDebug) { // imshow("Mask", cropMat); // cv::waitKey(0); //} cv::Mat m_HsvMat; cv::cvtColor(cropMat, m_HsvMat, COLOR_BGR2HSV); // 定义黑色的HSV范围 Scalar lower_black = Scalar(0, 0, 0); Scalar upper_black = Scalar(180, 255, 60); // 对于V的区域进行了确定 Mat mask; inRange(m_HsvMat, lower_black, upper_black, mask); //if (g_isDebug) { // cv::imshow("Mask", mask); // cv::waitKey(0); //} int whiteThreshold = 250; //定义白色的灰度阈值 根据需要调整阈值 int width = mask.cols, height = mask.rows; int whiteW = 0; for (int y = 0; y < height; ++y) { //先行后列 int whiteCount = 0; for (int x = 0; x < width; ++x) { if (x > 0 && mask.at(y, x) >= whiteThreshold && mask.at(y, x - 1) >= whiteThreshold) { // 判断是否是白色像素 ++whiteCount; // 这里可以根据需求处理白色像素,例如计数、修改像素值等 } else whiteCount = 0; whiteW = max(whiteCount + 1, whiteW); //要加上第一个像素点 } } // 遍历图像的每个像素 int whiteH = 0; for (int x = 0; x < width; ++x) { int whiteCount = 0; for (int y = 0; y < height; ++y) { if (y > 0 && mask.at(y, x) >= whiteThreshold && mask.at(y - 1, x) >= whiteThreshold) { // 判断是否是白色像素 ++whiteCount; // 这里可以根据需求处理白色像素,例如计数、修改像素值等 } else whiteCount = 0; whiteH = max(whiteCount + 1, whiteH); } } printf("whiteW:%d,whiteH:%d\n", whiteW, whiteH); m_knowLength = (int)(whiteW + whiteH) / 2; return; }