【7】OPencv骨架细化算法

1 骨架细化原理

思想:

公式: y = p0*2^0 + p1*2^1+ p2*2^2 + p3*2^3 + p4*2^4 + p5*2^5 + p6*2^6 +p7*2^7

         前辈们对此作出了总结,得出每个点周围8领域的256种情况,放在一个char data[256]的数组中,不可以删除用0来表示,能被删除的用1来表示。然后对图像进行处理得到二值图像<0和1>,扫描图像,根据公式得出y,依次用data[y]判断该点是否可以被删除,直到所有的点都不可以被删除为止。

算法流程图


原文:https://blog.csdn.net/lu597203933/article/details/14397605 

 


2 算法实现代码

// 骨架细化.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <vector>
#include "assert.h"

using namespace std;
using namespace cv;


Mat dst;
void Rosenfeld(Mat& src, Mat& dst)
{

	if (src.type() != CV_8UC1)
	{
		printf("只能处理二值或灰度图像\n");
		return;
	}
	//非原地操作时候,copy src到dst
	if (dst.data != src.data)
	{
		src.copyTo(dst);
	}

	int i, j, n;
	int width, height;
	//之所以减1,是方便处理8邻域,防止越界
	width = src.cols - 1;
	height = src.rows - 1;
	int step = src.step;
	int  p2, p3, p4, p5, p6, p7, p8, p9;
	uchar* img;
	bool ifEnd;
	Mat tmpimg;
	int dir[4] = { -step, step, 1, -1 };
	while (1)
	{
		//分四个子迭代过程,分别对应北,南,东,西四个边界点的情况
		ifEnd = false;
		for (n = 0; n < 4; n++)
		{
			dst.copyTo(tmpimg);
			img = tmpimg.data;
			for (i = 1; i < height; i++)
			{
				img += step;
				for (j = 1; j < width; j++)
				{
					uchar* p = img + j;
					//如果p点是背景点或者且为方向边界点,依次为北南东西,继续循环
					if (p[0] == 0 || p[dir[n]] > 0) continue;
					p2 = p[-step] > 0 ? 1 : 0;
					p3 = p[-step + 1] > 0 ? 1 : 0;
					p4 = p[1] > 0 ? 1 : 0;
					p5 = p[step + 1] > 0 ? 1 : 0;
					p6 = p[step] > 0 ? 1 : 0;
					p7 = p[step - 1] > 0 ? 1 : 0;
					p8 = p[-1] > 0 ? 1 : 0;
					p9 = p[-step - 1] > 0 ? 1 : 0;
					//8 simple判定
					int is8simple = 1;
					if (p2 == 0 && p6 == 0)
					{
						if ((p9 == 1 || p8 == 1 || p7 == 1) && (p3 == 1 || p4 == 1 || p5 == 1))
							is8simple = 0;
					}
					if (p4 == 0 && p8 == 0)
					{
						if ((p9 == 1 || p2 == 1 || p3 == 1) && (p5 == 1 || p6 == 1 || p7 == 1))
							is8simple = 0;
					}
					if (p8 == 0 && p2 == 0)
					{
						if (p9 == 1 && (p3 == 1 || p4 == 1 || p5 == 1 || p6 == 1 || p7 == 1))
							is8simple = 0;
					}
					if (p4 == 0 && p2 == 0)
					{
						if (p3 == 1 && (p5 == 1 || p6 == 1 || p7 == 1 || p8 == 1 || p9 == 1))
							is8simple = 0;
					}
					if (p8 == 0 && p6 == 0)
					{
						if (p7 == 1 && (p3 == 9 || p2 == 1 || p3 == 1 || p4 == 1 || p5 == 1))
							is8simple = 0;
					}
					if (p4 == 0 && p6 == 0)
					{
						if (p5 == 1 && (p7 == 1 || p8 == 1 || p9 == 1 || p2 == 1 || p3 == 1))
							is8simple = 0;
					}
					int adjsum;
					adjsum = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
					//判断是否是邻接点或孤立点,0,1分别对于那个孤立点和端点
					if (adjsum != 1 && adjsum != 0 && is8simple == 1)
					{
						dst.at<uchar>(i, j) = 0; //满足删除条件,设置当前像素为0
						ifEnd = true;
					}

				}
			}
		}
		if (!ifEnd) break;
	}

}

int main(int argc, char*argv[])
{

    Mat src = imread("06.jpg", 0);
	if (src.empty())
	{
		cout << "读取文件失败!" << std::endl;
		return -1;
	}
	resize(src, src, Size(src.cols / 2, src.rows / 2), (0, 0), (0, 0), 3);
	//将原图像转换为二值图像
	threshold(src, src, 20, 255, THRESH_BINARY_INV);//THRESH_BINARY_INV和 THRESH_BINARY不同对骨架细化有影响
	imshow("二值图像", src);
	//图像细化
	Rosenfeld(src, dst);
	//显示图像
	dst = dst * 255;
	imshow("未细化图片", src);
    imshow("细化图片", dst);
	waitKey(0);
	return 0;
}

效果图展示

原始图1(采用THRESH_BINARY_INV)

 效果图1

 

 原始图2(采用THRESH_BINARY)

 

 效果图2


注意 注意 注意!!!!!!!!!!!!

因为骨架细化算法输入的图片是二值化图片或者灰度图片  这里统一将图片定义为二值化图片后在输入:

如果前景是黑色背景是白色(即字符是黑色背景是白色) 使用THRESH_BINARY_INV(取反操作)二值化后(即字符是白色背景是黑色)

之后就可以将图片输入算法中进行骨架细化。

如果前景是白色背景是黑色(即字符是白色背景是黑色) 使用THRESH_BINARY二值化后(即字符是白色背景是黑色)

之后就可以将图片输入算法中进行骨架细化。

概括一下这个算法要求的设置是:待细化的图片前景是白色即用1表示;背景是黑色的用0表示 

即最后输入的照片一定是前景(要细化的细节)是白色背景是黑色(图片底色) 

也可以自己更改参数修改!!!!!!!!!!!!!

 

  • 10
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
根据提供的引用内容,有两种常见的基于OpenCV的图像增强算法可以使用C++实现: 1. 基于Retinex理论的图像增强算法:Retinex理论是一种常见的图像增强方法,它通过对图像的亮度和对比度进行调整来提高图像的质量。以下是一个使用OpenCV和C++实现的基于Retinex的图像增强算法的示例代码: ```cpp #include <opencv2/opencv.hpp> cv::Mat enhanceImage(cv::Mat image) { cv::Mat enhancedImage; // 使用Retinex算法增强图像 cv::xphoto::createSimpleRetinex()->apply(image, enhancedImage); return enhancedImage; } int main() { // 读取图像 cv::Mat image = cv::imread("image.jpg"); // 图像增强 cv::Mat enhancedImage = enhanceImage(image); // 显示增强后的图像 cv::imshow("Enhanced Image", enhancedImage); cv::waitKey(0); return 0; } ``` 2. Zhang-Suen细化算法:Zhang-Suen细化算法是一种用于提取图像骨架的二值图像处理算法。以下是一个使用OpenCV和C++实现的Zhang-Suen细化算法的示例代码: ```cpp #include <opencv2/opencv.hpp> cv::Mat thinningImage(cv::Mat image) { cv::Mat binaryImage; // 将图像转换为二值图像 cv::cvtColor(image, binaryImage, cv::COLOR_BGR2GRAY); cv::threshold(binaryImage, binaryImage, 128, 255, cv::THRESH_BINARY); // 使用Zhang-Suen细化算法提取图像骨架 cv::ximgproc::thinning(binaryImage, binaryImage, cv::ximgproc::THINNING_ZHANGSUEN); return binaryImage; } int main() { // 读取图像 cv::Mat image = cv::imread("image.jpg"); // 图像细化 cv::Mat thinnedImage = thinningImage(image); // 显示细化后的图像 cv::imshow("Thinned Image", thinnedImage); cv::waitKey(0); return 0; } ``` 请注意,以上示例代码仅为演示目的,实际使用时可能需要根据具体需求进行适当的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值