Remove glitches in binary images and extract skeleton lines

Remove glitches in binary image

Without changing the connectivity of each connected domain in the binary image, delete the burrs in the binary image and extract the skeleton line

overall code implementation

//连通域分析
bool connectedanalysis(std::vector<int> vPixelVal)
{
    
    
	if (vPixelVal.size() != 9)
		return true;

	int  p1, p2, p3, p4, p5, p6, p7, p8, p9;
	p1 = vPixelVal[0];
	p2 = vPixelVal[1];
	p3 = vPixelVal[2];
	p4 = vPixelVal[3];
	p5 = vPixelVal[4];
	p6 = vPixelVal[5];
	p7 = vPixelVal[6];
	p8 = vPixelVal[7];
	p9 = vPixelVal[8];
				   
	//8 simple判定
	if (p2 == 0 && p6 == 0)
	{
    
    
		if ((p9 == 255 || p8 == 255 || p7 == 255) && (p3 == 255 || p4 == 255 || p5 == 255))
			return false;
	}
	if (p4 == 0 && p8 == 0)
	{
    
    
		if ((p9 == 255 || p2 == 255 || p3 == 255) && (p5 == 255 || p6 == 255 || p7 == 255))
			return false;
	}
	if (p8 == 0 && p2 == 0)
	{
    
    
		if (p9 == 255 && (p3 == 255 || p4 == 255 || p5 == 255 || p6 == 255 || p7 == 255))
			return false;
	}
	if (p4 == 0 && p2 == 0)
	{
    
    
		if (p3 == 255 && (p5 == 255 || p6 == 255 || p7 == 255 || p8 == 255 || p9 == 255))
			return false;
	}
	if (p8 == 0 && p6 == 0)
	{
    
    
		if (p7 == 255 && (p9 == 255 || p2 == 255 || p3 == 255 || p4 == 255 || p5 == 255))
			return false;
	}
	if (p4 == 0 && p6 == 0)
	{
    
    
		if (p5 == 255 && (p7 == 255 || p8 == 255 || p9 == 255 || p2 == 255 || p3 == 255))
			return false;
	}
	return true;
}

//去除二值图像边缘的突出部
//uthreshold、vthreshold分别表示突出部的宽度阈值和高度阈值
//type代表突出部的颜色,0表示黑色,1代表白色
void delete_jut(cv::Mat& src, cv::Mat& dst, int uthreshold, int vthreshold, int type)
{
    
    
	src.copyTo(dst);
	int height = dst.rows;
	int width = dst.cols;
	int k;  //用于循环计数传递到外部
	for (int i = 1; i < height - 1; i++)
	{
    
    
		if (i==338)
		{
    
    
			int a = 0;
		}
		uchar* p = dst.ptr<uchar>(i);
		for (int j = 1; j < width - 1; j++)
		{
    
    
			if (type == 0) //背景为白色
			{
    
    
				//行消除 
				if (p[j] == 255 && p[j + 1] == 0)
				{
    
    
					if (j + uthreshold >= width)
					{
    
    
						for (int k = j + 1; k < width; k++)
							p[k] = 255;
					}
					else
					{
    
    
						for (k = j + 2; k <= j + uthreshold; k++)
						{
    
    
							if (p[k] == 255) break;
						}
						if (p[k] == 255)
						{
    
    
							for (int h = j + 1; h < k; h++)
								p[h] = 255;
						}
					}
				}
				//列消除
				if (p[j] == 255 && p[j + width] == 0)
				{
    
    
					if (i + vthreshold >= height)
					{
    
    
						for (k = j + width; k < j + (height - i)*width; k += width)
							p[k] = 255;
					}
					else
					{
    
    
						for (k = j + 2 * width; k <= j + vthreshold * width; k += width)
						{
    
    
							if (p[k] == 255) break;
						}
						if (p[k] == 255)
						{
    
    
							for (int h = j + width; h < k; h += width)
								p[h] = 255;
						}
					}
				}
			}
			else  //背景为黑色
			{
    
    
				//行消除:当前为0后一个为255的情况下
				if (p[j] == 0 && p[j + 1] == 255)
				{
    
    
					if (j + uthreshold >= width) //超过最大宽度,直接置为0
					{
    
    
						continue;
						//for (int k = j + 1; k < width; k++)
						//{
    
    
						//	p[k] = 0;
						//}
					}
					else //255的个数小于uthreshold,全部置0
					{
    
    
						bool found = false;
						for (k = j + 1; k <= j + uthreshold; k++) 
						{
    
    
							//发现突刺,需要删除
							if (p[k] == 0)
							{
    
    
								found = true;
								break;
							}
						}
						if (found) //准备删除
						{
    
    
							for (int h = j + 1; h < k; h++)
							{
    
    
								std::vector<int> vPixelVal;
								vPixelVal.push_back(p[h]);
								vPixelVal.push_back(p[h - width]);
								vPixelVal.push_back(p[h - width + 1]);
								vPixelVal.push_back(p[h + 1]);
								vPixelVal.push_back(p[h + width + 1]);
								vPixelVal.push_back(p[h + width]);
								vPixelVal.push_back(p[h + width - 1]);
								vPixelVal.push_back(p[h - 1]);
								vPixelVal.push_back(p[h - width - 1]);
								bool IsDelete = connectedanalysis(vPixelVal);
								if (IsDelete) //可以删除,删除后不影响连通性
									p[h] = 0;
							}
						}
					}
				}
				//列消除:当前为0下一个为255的情况下
				if (p[j] == 0 && p[j + width] == 255)
				{
    
    
					if (i + vthreshold >= height) //超过最大高度,直接置为0
					{
    
    
						continue;
						//for (k = j + width; k < j + (height - i)*width; k += width)
						//	p[k] = 0;
					}
					else //255的个数小于vthreshold,全部置0
					{
    
    
						bool found = false;
						for (k = j + width; k <= j + vthreshold * width; k += width)
						{
    
    
							//发现突刺,需要删除
							if (p[k] == 0)
							{
    
    
								found = true;
								break;
							}
						}
						if (found) //准备删除
						{
    
    
							for (int h = j + width; h < k; h += width)
							{
    
    
								std::vector<int> vPixelVal;
								vPixelVal.push_back(p[h]);
								vPixelVal.push_back(p[h - width]);
								vPixelVal.push_back(p[h - width + 1]);
								vPixelVal.push_back(p[h + 1]);
								vPixelVal.push_back(p[h + width + 1]);
								vPixelVal.push_back(p[h + width]);
								vPixelVal.push_back(p[h + width - 1]);
								vPixelVal.push_back(p[h - 1]);
								vPixelVal.push_back(p[h - width - 1]);
								bool IsDelete = connectedanalysis(vPixelVal);
								if (IsDelete) //可以删除,删除后不影响连通性
									p[h] = 0;
							}
						}
					}
				}
			}
		}
	}
}

Connectivity Guaranteed

Use the following eight-neighborhood representation:
insert image description here
Take 8-connectivity as an example: after we set the value of p1 to 0, the 8-connectivity of the surrounding 8 pixels will not be changed. In the following three figures, if p1=0, the 8-connectivity will be changed.
insert image description here
The following will not change the 8 connectivity. At this time, it can be said that the pixel p1 is 8 simple. For the
insert image description here
specific determination method, see the function of the above code connectedanalysis. If it is determined to be false, then the connectivity will be affected after deletion.

Guess you like

Origin blog.csdn.net/qq_38589460/article/details/128997412