一、算法需求
在白色背景下拍摄布料的照片,使用图像处理算法找到布料的内轮廓线,用于缝纫机自动缝纫下针

二、问题分析
上图的特点是背景区域为白色,目标缝纫区域基本为灰色或黑色。在目标缝纫区域存在一些白点或者白线,需要设法去除这些干扰因素。在得到完好的目标缝纫区域后,可以使用形态学算法求出目标轮廓线(具体为物体内靠近边缘的一条细线,不是外轮廓线)。
核心思想:使用中间图形(比目标图形更细一些的图形==目标图形腐蚀的结果)的外轮廓线(可以通过低通滤波、形态学差异等方法获取)指代目标图形的内轮廓线。
三、基本实现步骤
1、读取图像为灰度图并进行二值化 【imread(“filename”,0),0:灰度图模式】
2、进行开运算与形态学优化 【通过开运算删除白色小孔洞;通过deleteMinWhiteArea删除小面积孔洞;确保图形中只有一个连通域 】
3、第一次腐蚀,使图形变小,得到im3【 使图形变小】
4、第二次腐蚀,求im3的轮廓线 【 通过减法得到轮廓线】
四、实现过程
4.1 图像读取为二值图
使用imread(filepath,0)将图像读取为灰度图,然后使用threshold函数将图像进行二值化。
Mat bin_mat, open_mat , dilate_mat, im3,im4,im5;
Mat img = imread("D:\\Img_data\\04.bmp", 0);
resize(img, img,{ 800,800 });
threshold(img, bin_mat, 180, 255, THRESH_BINARY);
imshow("img", img);
imshow("bin_mat", bin_mat);
读取的灰度图如下所示


4.2 去除干扰因素
在4.1中分析出二值图中存在多个白色区域和白色噪点,需要设计算法去除这些干扰因素。对于白色噪点可以低通滤波器(中值滤波、均值滤波、高斯滤波等)或形态学算法(开运算或腐蚀)进行移除;对于面积较大的白色干扰因素可以使用连通域面积的方法进行移除;同时需要关注图像是否存在黑色的小连通域需要删除。
具体实现代码如下所示。其中deleteMinWhiteArea用于删除图像中低于面积阈值的连通域,deleteMinBlackArea用于删除图像中低于面积阈值的黑色连通域,两个函数均参考自https://hpg123.blog.csdn.net/article/details/126864086。
//通过开运算移除轮廓中的白色噪点
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
morphologyEx(bin_mat, open_mat, MORPH_OPEN, element);
imshow("open_mat", open_mat);
//通过连通域筛选保留主要轮廓
Mat im2 = deleteMinWhiteArea(open_mat, 5000);//形态学优化
imshow("删除白色干扰", im2);
Mat im2_delete_black = deleteMinBlackArea(im2, 5000);//形态学优化
imshow("删除黑色干扰", im2_delete_black);
开运算结果如下所示,可见其存在小面积黑色连通域和白色连通域需要删除



4.3 求内轮廓线
关键知识点:需要两次腐蚀才能求得内轮廓线。第一次腐蚀,使图形变小;第二次腐蚀,求目标轮廓线。
第一次腐蚀,使图形变小操作中需要注意的是,使用较大的结构元素对图像进行腐蚀,得到im3 (一个较小的轮廓)。
第二次腐蚀,使用一个3x3的结构元素对im3 (一个较小的轮廓)进行腐蚀,得到dilate_mat;使用dilate_mat-im3,即可得到im3的轮廓线(此轮廓线为目标图像的内轮廓线)。
故此,第一次腐蚀时结构元素的大小决定了最终内轮廓线与目标图形的距离。
实现代码即效果如下所示
//----进行两次腐蚀,得到布料的内轮廓线---
//第一次腐蚀,使图形变小,得到im3
cv::Mat element2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(25, 25));
morphologyEx(im2_delete_black, im3, MORPH_DILATE, element2);
//第二次腐蚀,求im3的轮廓线
cv::Mat element1 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
morphologyEx(im3, dilate_mat, MORPH_DILATE, element1);
im4 = dilate_mat - im3;
imshow("轮廓线", im4);
im5 = im4 + bin_mat;
imshow("最终效果", im5);


#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <vector>
#include <io.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include "MatTool.hpp"
using namespace std;
using namespace cv;
int main() {
/* 提取缝纫机下针轮廓线,具体为物体内靠近边缘的一条细线
核心思想:不能直接求轮廓线,要求小轮廓的轮廓线
基本步骤:
1、读取图像为灰度图并进行二值化 【imread("filename",0),0:灰度图模式】
2、进行开运算与 形态学优化 【通过开运算删除白色小孔洞;通过deleteMinWhiteArea删除小面积孔洞;
确保图形中只有一个连通域 】
3、第一次腐蚀,使图形变小,得到im3【 使图形变小】
4、第二次腐蚀,求im3的轮廓线 【 通过减法得到轮廓线】
*/
Mat bin_mat, open_mat , dilate_mat, im3,im4,im5;
Mat img = imread("D:\\Img_data\\04.bmp", 0);
resize(img, img,{ 800,800 });
threshold(img, bin_mat, 180, 255, THRESH_BINARY);
imshow("img", img);
imshow("bin_mat", bin_mat);
//通过开运算移除轮廓中的白色噪点
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
morphologyEx(bin_mat, open_mat, MORPH_OPEN, element);
imshow("open_mat", open_mat);
//通过连通域筛选保留主要轮廓
Mat im2 = deleteMinWhiteArea(open_mat, 5000);//形态学优化
imshow("删除白色干扰", im2);
Mat im2_delete_black = deleteMinBlackArea(im2, 5000);//形态学优化
imshow("删除黑色干扰", im2_delete_black);
//----进行两次腐蚀,得到布料的内轮廓线---
//第一次腐蚀,使图形变小,得到im3
cv::Mat element2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(25, 25));
morphologyEx(im2_delete_black, im3, MORPH_DILATE, element2);
//第二次腐蚀,求im3的轮廓线
cv::Mat element1 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
morphologyEx(im3, dilate_mat, MORPH_DILATE, element1);
im4 = dilate_mat - im3;
imshow("轮廓线", im4);
im5 = im4 + bin_mat;
imshow("最终效果", im5);
waitKey();
}