前言
今天在51Halcon中看到一个有意思的帖子,是查找图片中电容器件的个数,觉得挺有意思,就用OpenCV实现了一下,这里分享给大家。
帖子链接:https://www.51halcon.com/thread-4670-1-5.html
1. OpenCV主要步骤
原图(引用帖子链接图片):
主要实现步骤:
- 读取原图并转为灰度图
- 提取ROI区域,主要是去除图片左边缘以及右下角水印的影响
- OTSU阈值化
- 执行2次开运算,分割每个电容器件
- 执行3次膨胀操作,连接每个电容器件
- 使用带统计信息的连通域计算方法
- 输出电容器件的个数以及定位每个电容器件的粗略位置
2. OpenCV C++实现
#include <iostream>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\core.hpp>
#include <opencv2\imgproc.hpp>
#include <opencv2\highgui.hpp>
#include <vector>
using namespace cv;
int main()
{
std::string strImgFile = "C:\\Temp\\common\\Workspace\\Opencv\\images\\connected_domain.png";
Mat mSrc = imread(strImgFile);
CV_Assert(!mSrc.empty());
Mat mGray;
cvtColor(mSrc, mGray, COLOR_BGR2GRAY);
CV_Assert(!mGray.empty());
Mat mRoi = mGray(Rect(6, 1, mGray.cols - 6, mGray.rows - 35));
CV_Assert(!mRoi.empty());
imshow("roi", mRoi);
Mat mThresh;
threshold(mRoi, mThresh, 128, 255, THRESH_BINARY | THRESH_OTSU);
CV_Assert(!mThresh.empty());
imshow("thresh", mThresh);
Mat mKernel1 = getStructuringElement(MORPH_RECT, Size(5, 5));
Mat mMorph;
morphologyEx(mThresh, mMorph, MORPH_OPEN, mKernel1, Point(-1, -1), 2);
CV_Assert(!mMorph.empty());
imshow("open", mMorph);
Mat mKernel2 = getStructuringElement(MORPH_RECT, Size(30, 3));
morphologyEx(mMorph, mMorph, MORPH_DILATE, mKernel2, Point(-1, -1), 2);
imshow("dilate", mMorph);
//连通域信息统计
Mat mLabel = Mat::zeros(mMorph.size(), CV_32S);
CV_Assert(!mLabel.empty());
Mat mStats;//记录外接矩形信息,左上角坐标,宽度、高度、面积
Mat mCentroids;//记录外接矩形中心点
//label 0: background
int nLabelNums = connectedComponentsWithStats(mMorph, mLabel, mStats, mCentroids);
std::cout << "电容器件总数:" << nLabelNums-1 << std::endl;
Mat mResult = mSrc.clone();
for (int i = 1; i < nLabelNums; i++)
{
Vec2d center = mCentroids.at<Vec2d>(i, 0);
int x = mStats.at<int>(i, CC_STAT_LEFT);
int y = mStats.at<int>(i, CC_STAT_TOP);
int width = mStats.at<int>(i, CC_STAT_WIDTH);
int height = mStats.at<int>(i, CC_STAT_HEIGHT);
circle(mResult, Point(center[0], center[1]), 2, Scalar(0, 0, 255), -1);
rectangle(mResult, Rect(x + 6, y + 1, width, height), Scalar(255, 0, 255));
}
imshow("Result", mResult);
waitKey(0);
destroyAllWindows();
return 0;
}
3. 运行结果
总结
从结果可以看出,上文方法只能准确检测电容器件的个数,至于定位电容位置就不是很准确了,只能给出大致位置信息,如果有大神能给出更准确的定位方法,欢迎留言给出,谢谢!(深度学习需要大量图片,这里就没有考虑)