#if 0
m_Window.OpenWindow(
100,
100,
800,
600,
0,
"visible",
"");
HImage img("D:\\test.png");
m_Window.DispObj(img);
#endif
#if 0
try {
HImage img("D:\\2.png");
HTuple ch = img.CountChannels();
/*
1 灰度图
3 RGB彩图
*/
HImage gray = (ch == 3) ? img.Rgb1ToGray() : img;
CString str2;
str2.Format(_T("ch=%d"), ch.I());
AfxMessageBox(str2);
gray = gray.MedianImage("circle", 3, "mirrored");
HWindow win;
win.OpenWindow(
0,
0,
1000,
800,
0,
"visible",
"");
win.DispObj(gray);
// 边缘提取
HXLDCont contours = gray.EdgesSubPix(
"canny",
1,
20,
40);
// 看有多少条轮廓
HTuple numContours = contours.CountObj();
CString msg;
msg.Format(_T("轮廓数=%d"), numContours.I());
AfxMessageBox(msg);
if (numContours.I() < 1)
return;
// 取第一条轮廓
HXLDCont contour =
contours.SelectObj(1);
// 获取轮廓点
HTuple rows, cols;
contour.GetContourXld(
&rows,
&cols);
FILE* fp = fopen("D:\\contour.txt", "w");
for (int i = 0; i < rows.Length(); i++)
{
fprintf(fp, "%f,%f\n",
cols[i].D(),
rows[i].D());
}
fclose(fp);
// 点数
int len = rows.Length();
CString str;
str.Format(
_T("轮廓点数=%d"),
len);
AfxMessageBox(str);
//---------------------------------
// 手动按 row 排序
//---------------------------------
std::vector<std::pair<double, double>> pts;
for (int i = 0; i < len; i++)
{
pts.push_back(
std::make_pair(
rows[i].D(),
cols[i].D()));
}
std::sort(
pts.begin(),
pts.end(),
[](const std::pair<double, double>& a,
const std::pair<double, double>& b)
{
return a.first < b.first;
});
//---------------------------------
// 分10段找峰值
//---------------------------------
int M = 10;
int step = (int)pts.size() / M;
std::vector<std::pair<double, double>> peaks;
for (int k = 0; k < M; k++)
{
int start = k * step;
int end =
(k == M - 1) ?
(int)pts.size() :
(k + 1) * step;
double maxY = -1e9;
double maxX = 0;
for (int i = start; i < end; i++)
{
if (pts[i].second > maxY)
{
maxY = pts[i].second;
maxX = pts[i].first;
}
}
peaks.push_back(
std::make_pair(maxX, maxY));
}
//---------------------------------
// 显示
//---------------------------------
//HWindow win;
win.OpenWindow(
0,
0,
1000,
800,
0,
"visible",
"");
win.DispObj(gray);
win.SetColor("red");
for (size_t i = 0; i < peaks.size(); i++)
{
win.DispCross(
peaks[i].first,
peaks[i].second,
20,
0);
}
CString result;
result.Format(
_T("检测峰值=%d"),
(int)peaks.size());
AfxMessageBox(result);
}
catch(HException& e)
{
CString str;
str.Format(
_T("Error=%d\r\n%s"),
e.ErrorCode(),
CString(e.ErrorMessage().Text()));
AfxMessageBox(str);
}
#endif
#if 0
// 1. 读取图片
Mat img = imread("D:\\123.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
Mat img2(500, 500, CV_8UC3, Scalar(0, 0, 0));
// 2. 转灰度
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
// 3. 显示(OpenCV窗口)
imshow("原图", img2);
imshow("灰度图", gray);
waitKey(0);
#endif
#if 0
// 1. 读取图片
cv::Mat img = cv::imread("D:\\123.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
// 2. 转灰度
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
// 3. 二值化输出
cv::Mat bin;
bool ok = Cvt2BinaryIm(gray, bin,
200, // separator(上半区/下半区分界)
120, // 上区域阈值
80); // 下区域阈值
if (!ok)
{
AfxMessageBox(_T("二值化失败"));
return;
}
// 4. 显示
cv::imshow("原图", img);
cv::imshow("灰度图", gray);
cv::imshow("二值图", bin);
cv::waitKey(0);
#endif
#if 0
// 1. 读取图片
cv::Mat img = cv::imread("D:\\123.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
// 2. 输出Mask
cv::Mat mask;
// 3. 调用
bool ok = modelMask(
img, // 输入图
mask, // 输出Mask
500, // 输出高度
500); // 输出宽度
if (!ok)
{
AfxMessageBox(_T("Mask生成失败"));
return;
}
// 4. 显示结果
cv::imshow("原图", img);
cv::imshow("Mask", mask);
cv::waitKey(0);
#endif
#if 0
// 1. 读取图片
cv::Mat img = cv::imread("D:\\123.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
// 2. 生成Mask
cv::Mat mask;
bool ok = modelMask(
img,
mask,
500,
500);
if (!ok)
{
AfxMessageBox(_T("Mask生成失败"));
return;
}
// 3. 查找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(
mask,
contours,
hierarchy,
cv::RETR_EXTERNAL,
cv::CHAIN_APPROX_SIMPLE);
CString str;
str.Format(_T("轮廓数量=%d"), (int)contours.size());
AfxMessageBox(str);
// 4. 绘制轮廓
cv::Mat result;
cv::cvtColor(mask, result, cv::COLOR_GRAY2BGR);
for (size_t i = 0; i < contours.size(); i++)
{
double area = cv::contourArea(contours[i]);
// 过滤小噪声
if (area < 50)
continue;
cv::drawContours(
result,
contours,
(int)i,
cv::Scalar(0, 0, 255),
2);
}
cv::imshow("原图", img);
cv::imshow("Mask", mask);
cv::imshow("轮廓", result);
cv::waitKey(0);
#endif
#if 0
// 1. 读取图片
cv::Mat img = cv::imread("D:\\123.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
// 2. 生成Mask
cv::Mat mask;
bool ok = modelMask(
img,
mask,
500,
500);
if (!ok)
{
AfxMessageBox(_T("Mask生成失败"));
return;
}
// 3. 查找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(
mask,
contours,
hierarchy,
cv::RETR_EXTERNAL,
cv::CHAIN_APPROX_SIMPLE);
CString str;
str.Format(_T("轮廓数量=%d"), (int)contours.size());
AfxMessageBox(str);
cv::Mat labels;
int count = cv::connectedComponents(
mask,
labels,
8);
str.Format(
_T("连通域数量=%d"),
count - 1); // 减去背景
AfxMessageBox(str);
cv::imshow("原图", img);
cv::imshow("Mask", mask);
cv::waitKey(0);
#endif
#if 0
// 1. 读取图片
cv::Mat img = cv::imread("D:\\55.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
// 2. 生成Mask
cv::Mat mask;
bool ok = modelMask(
img,
mask,
500,
500);
if (!ok)
{
AfxMessageBox(_T("Mask生成失败"));
return;
}
//去噪
cv::Mat kernel =
cv::getStructuringElement(
cv::MORPH_RECT,
cv::Size(3, 3));
cv::morphologyEx(
mask,
mask,
cv::MORPH_OPEN,
kernel);
//连通
cv::morphologyEx(
mask,
mask,
cv::MORPH_CLOSE,
kernel);
// 3. 查找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(
mask,
contours,
hierarchy,
cv::RETR_EXTERNAL,
cv::CHAIN_APPROX_SIMPLE);
cv::Mat labels;
cv::Mat stats;
cv::Mat centroids;
int numLabels =
cv::connectedComponentsWithStats(
mask,
labels,
stats,
centroids,
8);
int lnum = 0;
#if 0
for (int i = 1; i < numLabels; i++)
{
int area =
stats.at<int>(
i,
cv::CC_STAT_AREA);
if (area > 5000)
lnum++;
}
str.Format(
_T("螺栓数量=%d"),
lnum); // 减去背景
AfxMessageBox(str);
#endif
cv::Mat result;
cv::cvtColor(mask, result, cv::COLOR_GRAY2BGR);
for (int i = 1; i < numLabels; i++)
{
int area =
stats.at<int>(
i,
cv::CC_STAT_AREA);
if (area < 70)
{
continue;
}
lnum++;
int left = stats.at<int>(i, cv::CC_STAT_LEFT);
int top = stats.at<int>(i, cv::CC_STAT_TOP);
int width = stats.at<int>(i, cv::CC_STAT_WIDTH);
int height = stats.at<int>(i, cv::CC_STAT_HEIGHT);
cv::rectangle(
result,
cv::Rect(left, top, width, height),
cv::Scalar(0, 0, 255),
2);
cv::putText(
result,
std::to_string(i),
cv::Point(left, top - 5),
cv::FONT_HERSHEY_SIMPLEX,
0.6,
cv::Scalar(0, 255, 0),
2);
}
CString str;
str.Format(
_T("番茄数量=%d"),
lnum); // 减去背景
AfxMessageBox(str);
cv::imshow("Result", result);
#if 0
std::ofstream fout("D:\\result.txt");
if (!fout.is_open())
{
AfxMessageBox(_T("文件打开失败"));
return;
}
for (int i = 1; i < numLabels; i++)
{
int area =
stats.at<int>(
i,
cv::CC_STAT_AREA);
fout << "区域"
<< i
<< " 面积="
<< area
<< std::endl;
}
fout.close();
#endif
cv::imshow("原图", img);
cv::imshow("Mask", mask);
cv::waitKey(0);
#endif
#if 0
// 1. 读取图像
cv::Mat img = cv::imread("D:\\44.png");
if (img.empty())
{
AfxMessageBox(_T("图片加载失败"));
return;
}
// 2. BGR → HSV
cv::Mat hsv;
cv::cvtColor(img, hsv, cv::COLOR_BGR2HSV);
// 3. 拆分通道
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
cv::Mat h = channels[0];
cv::Mat s = channels[1];
cv::Mat v = channels[2];
// 4. 调用单例
cv::Mat mask =
HSVThresholder::instance().getMask(h, s, v);
//去噪
cv::Mat kernel =
cv::getStructuringElement(
cv::MORPH_RECT,
cv::Size(3, 3));
cv::morphologyEx(
mask,
mask,
cv::MORPH_OPEN,
kernel);
//连通
cv::morphologyEx(
mask,
mask,
cv::MORPH_CLOSE,
kernel);
// 3. 查找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(
mask,
contours,
hierarchy,
cv::RETR_EXTERNAL,
cv::CHAIN_APPROX_SIMPLE);
CString str;
str.Format(_T("轮廓数量=%d"), (int)contours.size());
AfxMessageBox(str);
// 5. 显示结果
cv::imshow("Original", img);
cv::imshow("HSV Mask (R+B+Y)", mask);
cv::waitKey(0);
#endif