C++ OpenCV實(shí)戰(zhàn)之網(wǎng)孔檢測的實(shí)現(xiàn)
前言
前段時間,有位粉絲私信我,給我發(fā)了一張圖片,如下圖所示:
在這里貼出他的原話。
從他給的圖片分析,該圖存在遮擋,所以不能簡單的二值化,然后提取圖像輪廓去尋找結(jié)果。所以,我就想如何去掉這些遮擋物(即圖像修復(fù))。從圖像可知,該遮擋物是黃色的線,所以,我就想可否使用hsv色彩空間提取出黃色,然后得到二值掩模圖像,最后對原圖進(jìn)行修復(fù)。接下來,就一起看看是如何一步步實(shí)現(xiàn)的吧。
一、HSV通道轉(zhuǎn)換
通過hsv通道轉(zhuǎn)換,可以提取出圖像中的黃色分量。
//hsv顏色通道轉(zhuǎn)換,提取圖像中黃色線部分,生成掩膜圖像 Mat hsv; cvtColor(src, hsv, COLOR_BGR2HSV); Mat mask; inRange(hsv, Scalar(10, 50, 255), Scalar(40, 255, 255), mask);
結(jié)果如圖所示:
二、圖像修復(fù)
關(guān)于圖像修復(fù)的相關(guān)知識可以參考我之前的博文。這里就不細(xì)說了。
OpenCV C++案例實(shí)戰(zhàn)十四《圖像修復(fù)》
OpenCV C++案例實(shí)戰(zhàn)十七《圖像去水印》
我們拿到上面的mask掩模圖像,需要對其進(jìn)行膨脹處理,使修復(fù)區(qū)域范圍擴(kuò)大。
//將生成的掩膜mask膨脹一下,使掩膜區(qū)域放大 Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9)); dilate(mask, mask, kernel);
接下來,需要對圖像進(jìn)行修復(fù)。這里我提供兩種修復(fù)方法,一種是OpenCV提供的inpaint函數(shù),一種是我自己寫的。
2.1 OpenCV函數(shù)實(shí)現(xiàn)
//使用OpenCV自帶的inpaint函數(shù)進(jìn)行圖像修復(fù),得到目標(biāo)圖像 Mat inpaintImg; inpaint(src, mask, inpaintImg, 1, INPAINT_NS);
效果如圖所示。
2.2 MyFunction
通過修改圖像像素達(dá)到圖像修復(fù)的效果。具體請看源碼注釋。
//自己寫的算法,修改圖像像素,完成圖像修復(fù) Mat canvas = Mat::zeros(src.size(), src.type()); int r = 1;//像素查找范圍--表示在該像素點(diǎn)上下幾行像素進(jìn)行查找 for (int i = r; i < src.rows- r; i++) { for (int j = 0; j < src.cols; j++) { if (mask.at<uchar>(i, j) != 255) { //對于非掩膜區(qū)域,直接將原像素進(jìn)行像素賦值 for (int c = 0; c < 3; c++) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(i, j)[c]; } } else { //找到距離該掩膜像素點(diǎn)最近的非掩膜區(qū)域像素進(jìn)行賦值 Point res = find_Nearest_Point(mask, i, j, r); for (int c = 0; c < 3; c++) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(res.x, res.y)[c]; } } } }
效果如何所示
三、輪廓提取
接下來我們只需要對修復(fù)之后的圖像進(jìn)行輪廓提取就可以了。
//將修復(fù)之后的目標(biāo)圖像進(jìn)行圖像預(yù)處理,提取輪廓 Mat gray; cvtColor(canvas, gray, COLOR_BGR2GRAY); Mat gaussian; GaussianBlur(gray, gaussian, Size(3, 3), 0); Mat thresh; threshold(gaussian, thresh, 30, 255, THRESH_BINARY_INV); Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(thresh, thresh, MORPH_OPEN, kernel); //namedWindow("thresh", WINDOW_NORMAL); //imshow("thresh", thresh); //輪廓提取 vector<vector<Point>>contours; findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //經(jīng)過面積,外接矩形特征篩選出目標(biāo)區(qū)域 vector<vector<Point>>EffectiveConts; for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area>100) { Rect rect = boundingRect(contours[i]); if (double(rect.height) > 30 && double(rect.width) > 30) { EffectiveConts.push_back(contours[i]); } } }
四、效果顯示
for (int i = 0; i < EffectiveConts.size(); i++) { //計(jì)算輪廓矩 Moments Mo = moments(EffectiveConts[i]); //計(jì)算質(zhì)心--即插孔坐標(biāo) Point center = Point(Mo.m10 / Mo.m00, Mo.m01 / Mo.m00); //效果繪制 Rect rect = boundingRect(EffectiveConts[i]); rectangle(src, rect, Scalar(0, 255, 0), 5); circle(src, center, 3, Scalar(0, 0, 255), -1); }
如圖為該案例最終效果。
五、源碼
#include<opencv2/opencv.hpp> #include <iostream> #include<opencv2/photo.hpp> using namespace std; using namespace cv; double EuDis(Point pt1, Point pt2) { return sqrt(pow(pt1.x - pt2.x, 2) + pow(pt1.y - pt2.y, 2)); } Point find_Nearest_Point(Mat mask , int currentrow, int currentcol, int r) { double mindis = 100000.0; Point res(0,0); //查找該像素點(diǎn)上下r行像素,找到最接近該像素的非掩膜區(qū)域像素 for (int i = currentrow - r; i < currentrow + r; i++) { for (int j = 0; j < mask.cols; j++) { if (mask.at<uchar>(i, j) != 255) { //Point(currentrow, currentcol) 表示當(dāng)前需要賦值的掩膜像素點(diǎn) double dis = EuDis(Point(currentrow, currentcol), Point(i, j)); if (dis < mindis) { mindis = dis; res = Point(i, j); //目標(biāo)像素點(diǎn) } } } } return res; } int main() { Mat src = imread("test.jpg"); if (src.empty()) { cout << "No Image!" << endl; system("pause"); return -1; } //hsv顏色通道轉(zhuǎn)換,提取圖像中黃色線部分,生成掩膜圖像 Mat hsv; cvtColor(src, hsv, COLOR_BGR2HSV); Mat mask; inRange(hsv, Scalar(10, 50, 255), Scalar(40, 255, 255), mask); //將生成的掩膜mask膨脹一下,使掩膜區(qū)域放大 Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9)); dilate(mask, mask, kernel); //使用OpenCV自帶的inpaint函數(shù)進(jìn)行圖像修復(fù),得到目標(biāo)圖像 //Mat inpaintImg; //inpaint(src, mask, inpaintImg, 1, INPAINT_NS); //namedWindow("inpaintImg", WINDOW_NORMAL); //imshow("inpaintImg", inpaintImg); //自己寫的算法,修改圖像像素,完成圖像修復(fù) Mat canvas = Mat::zeros(src.size(), src.type()); int r = 1;//像素查找范圍--表示在該像素點(diǎn)上下幾行像素進(jìn)行查找 for (int i = r; i < src.rows- r; i++) { for (int j = 0; j < src.cols; j++) { if (mask.at<uchar>(i, j) != 255) { //對于非掩膜區(qū)域,直接將原像素進(jìn)行像素賦值 for (int c = 0; c < 3; c++) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(i, j)[c]; } } else { //找到距離該掩膜像素點(diǎn)最近的非掩膜區(qū)域像素進(jìn)行賦值 Point res = find_Nearest_Point(mask, i, j, r); for (int c = 0; c < 3; c++) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(res.x, res.y)[c]; } } } } //namedWindow("canvas", WINDOW_NORMAL); //imshow("canvas", canvas); //將修復(fù)之后的目標(biāo)圖像進(jìn)行圖像預(yù)處理,提取輪廓 Mat gray; cvtColor(canvas, gray, COLOR_BGR2GRAY); Mat gaussian; GaussianBlur(gray, gaussian, Size(3, 3), 0); Mat thresh; threshold(gaussian, thresh, 30, 255, THRESH_BINARY_INV); Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(thresh, thresh, MORPH_OPEN, kernel); //namedWindow("thresh", WINDOW_NORMAL); //imshow("thresh", thresh); //輪廓提取 vector<vector<Point>>contours; findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //經(jīng)過面積,外接矩形特征篩選出目標(biāo)區(qū)域 vector<vector<Point>>EffectiveConts; for (int i = 0; i < contours.size(); i++) { double area = contourArea(contours[i]); if (area>100) { Rect rect = boundingRect(contours[i]); if (double(rect.height) > 30 && double(rect.width) > 30) { EffectiveConts.push_back(contours[i]); } } } for (int i = 0; i < EffectiveConts.size(); i++) { //計(jì)算輪廓矩 Moments Mo = moments(EffectiveConts[i]); //計(jì)算質(zhì)心--即插孔坐標(biāo) Point center = Point(Mo.m10 / Mo.m00, Mo.m01 / Mo.m00); //效果繪制 Rect rect = boundingRect(EffectiveConts[i]); rectangle(src, rect, Scalar(0, 255, 0), 5); circle(src, center, 3, Scalar(0, 0, 255), -1); } namedWindow("src", WINDOW_NORMAL); imshow("src", src); waitKey(0); system("pause"); return 0; }
總結(jié)
本文使用OpenCV C++實(shí)現(xiàn)網(wǎng)孔檢測,主要操作有以下幾點(diǎn)。
1、hsv通道轉(zhuǎn)換,提取出黃色分量,得到掩模圖像。
2、利用掩模圖像對原圖進(jìn)行圖像修復(fù)。
3、通過輪廓提取定位網(wǎng)孔位置。
以上就是C++ OpenCV實(shí)戰(zhàn)之網(wǎng)孔檢測的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于C++ OpenCV網(wǎng)孔檢測的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用C++ Matlab中的lp2lp函數(shù)教程詳解
本文介紹如何使用C++編寫數(shù)字濾波器設(shè)計(jì)算法,實(shí)現(xiàn)Matlab中的lp2lp函數(shù),將低通濾波器轉(zhuǎn)換為參數(shù)化的低通濾波器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-04-04C語言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)希爾排序算法
這篇文章主要為大家介紹了C語言希爾排序算法實(shí)現(xiàn)植物大戰(zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05VC中實(shí)現(xiàn)GB2312、BIG5、Unicode編碼轉(zhuǎn)換的方法
這篇文章主要介紹了VC中實(shí)現(xiàn)GB2312、BIG5、Unicode編碼轉(zhuǎn)換的方法,該功能非常實(shí)用,需要的朋友可以參考下2014-07-07C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(6.字型轉(zhuǎn)換字符串),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07