Measure/DN_sample/MicroImage.cpp

503 lines
13 KiB
C++
Raw Normal View History

2024-07-18 09:50:08 +08:00
#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<Vec3b>(y, x);
if (pc[0] != 0 || pc[1] != 0 || pc[2] != 0) {
pc[0] = 0; pc[1] = 0; pc[2] = 0;
}
}
}
}
void MicroImage::StatisticsBGColor() {
2024-07-18 18:17:33 +08:00
Rect cropRect1(m_width / 2 - 40, m_height / 2 - 40, 80, 80); // 中心位置
2024-07-18 09:50:08 +08:00
cropRect1 &= Rect(0, 0, m_width, m_height); // 检查ROI是否在图像范围内
Mat cropMat1 = m_image(cropRect1);
2024-07-18 18:17:33 +08:00
Rect cropRect2(0, m_height / 2 - 25, 50, 50); //中左位置
cropRect2 &= Rect(0, 0, m_width, m_height);
2024-07-18 09:50:08 +08:00
Mat cropMat2 = m_image(cropRect2);
2024-07-18 18:17:33 +08:00
Rect cropRect3(m_width - 25, m_height / 2 - 25, 50, 50); //中右位置
cropRect3 &= Rect(0, 0, m_width, m_height);
2024-07-18 09:50:08 +08:00
Mat cropMat3 = m_image(cropRect3);
2024-07-18 18:17:33 +08:00
Rect cropRect4(0, 0, 25, 25); //左上角位置
cropRect4 &= Rect(0, 0, m_width, m_height);
2024-07-18 09:50:08 +08:00
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<Vec3b>(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<Vec3b>(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<Vec3b>(yy, x);
pixel[0] = 0;
pixel[1] = 0;
pixel[2] = 255;
}
}
}
bool MicroImage::IslandCheck(int y, int x, std::set<int>& tempSet) {
tempSet.insert((y << 16) | x);
queue<int> 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<Vec3b>(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<Vec3b>(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<Vec3b>(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<Vec3b>(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<Point> 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<Vec3b>(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<Vec3b>(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<Vec3b>(y, x);
if ((pc[0] != 0 || pc[1] != 0 || pc[2] != 0)) { //非黑色
return false;
}
return true;
}
void MicroImage::IsLandRemove() {
set<int> tempSet;
set<int> 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<Vec3b>(((*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<Vec3b>(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<Vec3b>(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<Vec3b>(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<Vec3b>(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);
2024-07-18 18:17:33 +08:00
//StandardLineDetect(); //标准线段检测 先固定值
2024-07-18 09:50:08 +08:00
StatisticsBGColor();
SquareRemove();
2024-07-18 18:17:33 +08:00
//#if 0
// IsLandRemove();
// Binarization();
//
//#endif
2024-07-18 09:50:08 +08:00
int dx = 0, dy = 0;
CalBorderCrop(dx, dy);
2024-07-18 18:17:33 +08:00
m_knowLength = 148; //先固定
2024-07-18 09:50:08 +08:00
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<uchar>(y, x) >= whiteThreshold && mask.at<uchar>(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<uchar>(y, x) >= whiteThreshold && mask.at<uchar>(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;
}