IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 去毛刺 zishu zishu -> 正文阅读

[数据结构与算法]去毛刺 zishu zishu

1 算法流程

本算法适用领域为以某种方式细化后的图像。

算法的主要思路就是将所有分支与毛刺都看成不同长度的分支,如果分支长度过短小于一定长度就认为是毛刺被去掉。每一个分支的结尾点都是一个端点。算法具体流程:

1)遍历所有连通区所有点,找到所有端点,端点的定义为其8邻域点只有一个像素点,如下图红色像素点八邻域内只有黑色点一个像素点,那么判断红色点为端点。

2)遍历每一个端点,直到遍历到该分支的起始点也就是分岔点,分岔点定义为:经过细化后,8邻域的像素点个数大于等于3的点,统计每个分支的长度,长度小于阈值T的分支被认为是毛刺分支。

3)将毛刺分支擦除。

2 代码

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>

using namespace cv;
using namespace std;

//找8邻域点
int Get8NeighborPt(cv::Mat mSrc, cv::Point point, std::vector<cv::Point> &vPoint)
{
	if (0 == mSrc.ptr<uchar>(point.y)[point.x])
	{
		return 0;
	}
	vPoint.clear();
	cv::Point point1, point2, point3, point4, point5, point6, point7, point8;

	point1.x = point.x - 1;
	point1.y = point.y - 1;
	int nValuePt1 = mSrc.ptr<uchar>(point1.y)[point1.x];
	point2.x = point.x;
	point2.y = point.y - 1;
	int nValuePt2 = mSrc.ptr<uchar>(point2.y)[point2.x];
	point3.x = point.x + 1;
	point3.y = point.y - 1;
	int nValuePt3 = mSrc.ptr<uchar>(point3.y)[point3.x];
	point4.x = point.x - 1;
	point4.y = point.y;
	int nValuePt4 = mSrc.ptr<uchar>(point4.y)[point4.x];
	point5.x = point.x + 1;
	point5.y = point.y;
	int nValuePt5 = mSrc.ptr<uchar>(point5.y)[point5.x];
	point6.x = point.x - 1;
	point6.y = point.y + 1;
	int nValuePt6 = mSrc.ptr<uchar>(point6.y)[point6.x];
	point7.x = point.x;
	point7.y = point.y + 1;
	int nValuePt7 = mSrc.ptr<uchar>(point7.y)[point7.x];
	point8.x = point.x + 1;
	point8.y = point.y + 1;
	int nValuePt8 = mSrc.ptr<uchar>(point8.y)[point8.x];

	if (255 == nValuePt1)
	{
		vPoint.push_back(point1);
	}
	if (255 == nValuePt2)
	{
		vPoint.push_back(point2);
	}
	if (255 == nValuePt3)
	{
		vPoint.push_back(point3);
	}
	if (255 == nValuePt4)
	{
		vPoint.push_back(point4);
	}
	if (255 == nValuePt5)
	{
		vPoint.push_back(point5);
	}
	if (255 == nValuePt6)
	{
		vPoint.push_back(point6);
	}
	if (255 == nValuePt7)
	{
		vPoint.push_back(point7);
	}
	if (255 == nValuePt8)
	{
		vPoint.push_back(point8);
	}
	int nFlagEdgePt = vPoint.size();

	return nFlagEdgePt;
}

//找端点
void FindTerminalPt(cv::Mat mSrc, std::vector<cv::Point> &vTerminalPt)
{
	int nWidth, nHeight;
	for (nHeight = 1; nHeight < mSrc.rows - 1; nHeight++)
	{
		for (nWidth = 1; nWidth < mSrc.cols - 1; nWidth++)
		{
			uchar nValuePt1 = mSrc.ptr<uchar>(nHeight)[nWidth];
			cv::Point point;
			point.x = nWidth;
			point.y = nHeight;
			std::vector<cv::Point> vPoint;
			if (1 == Get8NeighborPt(mSrc, point, vPoint))
			{
				vTerminalPt.push_back(point);
			}
		}
	}
}

//去毛刺统计每个分支的长度,小于阈值nTBurr的分支被认为是毛刺分支。
void RemoveBurr(cv::Mat mSrc, cv::Mat &mDst, int nTBurr = 20)
{
	mDst = mSrc.clone();
	std::vector<cv::Point> vTerminalPt;
	FindTerminalPt(mSrc, vTerminalPt);
	cv::Point LastPt, NextPt;
	int nLenthBranch = 0;
	bool bFlagEnd = true;
	for (int nIndex = 0; nIndex < vTerminalPt.size(); nIndex++)
	{
		LastPt = vTerminalPt[nIndex];
		NextPt = vTerminalPt[nIndex];
		nLenthBranch = 0;
		bFlagEnd = true;
		std::vector<cv::Point> vBurrPt;
		while (bFlagEnd)
		{
			std::vector<cv::Point> vPoint;
			if (1 == Get8NeighborPt(mSrc, NextPt, vPoint))
			{
				vBurrPt.push_back(NextPt);
				LastPt = NextPt;
				NextPt = vPoint[0];
				nLenthBranch++;
			}
			else if (2 == Get8NeighborPt(mSrc, NextPt, vPoint))
			{
				vBurrPt.push_back(NextPt);
				if (LastPt != vPoint[0])
				{
					LastPt = NextPt;
					NextPt = vPoint[0];
				}
				else
				{
					LastPt = NextPt;
					NextPt = vPoint[1];
				}
				nLenthBranch++;
			}
			else if (3 <= Get8NeighborPt(mSrc, NextPt, vPoint))
			{
				bFlagEnd = false;
			}

			if (nLenthBranch > nTBurr)
			{
				bFlagEnd = false;
			}
		}

		if (nLenthBranch < nTBurr)
		{
			int nIndexBurr = 0;
			for (nIndexBurr = 0; nIndexBurr < vBurrPt.size(); nIndexBurr++)
			{
				mDst.ptr<uchar>(vBurrPt[nIndexBurr].y)[vBurrPt[nIndexBurr].x] = 0;
			}
		}
	}
}

int main(int argc, char** argv)
{
	cv::Mat src_bin = imread("毛刺.jpg", IMREAD_GRAYSCALE);
	threshold(src_bin, src_bin, 120,255, THRESH_BINARY);
	cv::imshow("src_bin", src_bin);
	cv::Mat result;
	RemoveBurr(src_bin, result);
	cv::imshow("result", result);

	waitKey(0);
	return 0;
}

3 效果

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:36:03  更:2022-04-04 12:39:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:56:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码