2016-07-03 21:03:51 qq_26499769 阅读数 10198
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    30543 人正在学习 去看看 张中强
之前见了一些文章讨论了一些有趣的图像处理算法
下面总结列出:

在研究的过程中,有时候会碰到很多有意思的图像处理算法,算法极具新意,并且能够产生非常有意思的结果。

算法简介
1、图像镶嵌

图像镶嵌也叫图像混合(Image Blending)、图像剪接(Image Editing),是通过特定的图像处理方法将本来毫无关系的两幅图无缝剪辑到一起,并能够很好地融合两者之间的剪接处,产生以假乱真的效果,不信我们就来看看。

上图左边的手和嘴巴在两幅不同的图中,只要给定一个模板,就可以把一幅图中模板指定的部分无缝拼接到另外一幅图中去,从右边的结果来看是不是看上去毫无违和感?比某些人的PS技术强多了。

类似剪接效果的还有下面这种技术,该算法同样也是划定一个区域,能够将两幅图中的指定区域图像都拿出来,拼接到第三幅图上去,结果简直天衣无缝。这两个算法的技术细节可看参考文献[1][2]。同样也可以参考这位小哥的代码

2、黑白图像着色

家里有黑白的老照片,想把它变成彩色照片,看看老一辈人真实的模样,那你可以试试下面这个图像着色(Colorization)算法。你只要拿彩笔在图像上画几笔,剩下的事情就交给算法啦。这个算法除了给黑白图片着色,还能够给视频着色呢!不信就去文献[3]看看。

3、图像超分辨

还记得小时候的红白机画面么,分辨率很低,如果放大的话,渣渣的马赛克就来了,想不起来了?想想《愤怒的小鸟》那个游戏里面马赛克小鸟,实在让人心塞,如果用了这个算法效果绝对就不一样了。该超分辨算法能够将分辨率非常低的图像提取与分辨率无关的向量,最后的高分辨率图像真是碉堡了,完虐普通的最近邻插值法放大的图像。还有人提供了Python源代码呢。

4、图像去模糊

拍照片的时候手抖,拍出来的照片模糊了怎么办?可以背个三脚架,或者花钱升级相机,变成防抖的。或者你也可以使用以下的图像处理方法,拍完之后处理,就可以得到清晰的图像了。说不定哪一天珍贵的一瞬间拍模糊了,还能用来救救急。

5、图像编辑

要是拍照的时候把不需要的物体拍进来了,破坏了照片美好的意境怎么办?此时,你可能需要这种图像处理技术[6][7]:将图像中意外出现的东西去掉!看下图,前提是要指定需要去掉的区域(中间一幅Mask图像)。

如果拍上去的建筑物看上去破破烂烂的,想填补一下这个破洞,或者想干脆在图像中再复制同一个物体,可以试试下面这个方法[7][8]。顺便说一句,这两个方法都应用到了PhotoShop上了。


参考文献

[1] Peter J. Burt and Edward H. Adelson. 1983. A multiresolution spline with application to image mosaics. ACM Trans. Graph. 2, 4 (October 1983)

[2] Patrick Pérez, Michel Gangnet, and Andrew Blake. 2003. Poisson image editing. ACM Trans. Graph. 22, 3 (July 2003)

[3] Anat Levin, Dani Lischinski, and Yair Weiss. 2004. Colorization using optimization. ACM Trans. Graph. 23, 3 (August 2004)

[4] Johannes Kopf and Dani Lischinski. 2011. Depixelizing Pixel ArtACM Transactions on Graphics (Proceedings of SIGGRAPH 2011).

[5] Xu, Li, and Jiaya Jia. 2010. Two-phase kernel estimation for robust motion deblurring.ECCV. Springer Berlin Heidelberg, 2010. 157-170.

[6] Image Completion

[7] Y. Wexler, E. Shechtman and M. Irani "Space-Time Video Completion" Computer Vision and Pattern Recognition (CVPR), Washington, June 2004.

[8] Connelly Barnes, Eli Shechtman, Adam Finkelstein, and Dan B Goldman. 2009.PatchMatch: a randomized correspondence algorithm for structural image editing. ACM Trans. Graph. 28, 3, Article 24 (July 2009)

[9] Connelly Barnes, Eli Shechtman, Dan B Goldman, The Generalized PatchMatch Correspondence Algorithm, ECCV, 2010





还有一篇:


一、像素图生成向量图的算法

数字时代早期的图片,分辨率很低。尤其是一些电子游戏的图片,放大后就是一个个像素方块。
Depixelizing(http://research.microsoft.com/en-us/um/people/kopf/pixelart/)算法可以让低分辨率的像素图转化为高质量的向量图。

二、黑白图片的着色算法

让老照片自动变成彩色的算法(http://www.cs.huji.ac.il/~yweiss/Colorization/)。

三、消除阴影的算法

不留痕迹地去掉照片上某件东西的阴影的算法(http://www.cs.huji.ac.il/~danix/ShadowRemoval/index.html)。

四、HDR照片的算法

所谓"HDR照片",就是让明亮处变得更亮、让阴暗处变得更暗,从而让照片产生强烈的对比效果。

实现HDR的软件有很多,这里推荐G'MIC(http://gmic.eu/)。它是GIMP图像编辑软件的一个插件,代码全部开源。

五、消除杂物的算法

所谓"消除杂物",就是在照片上划出一块区域,然后用背景自动填补。Resynthesizer可以做到这一点,它也是GIMP的一个插件。

六、自动合成照片的算法


根据一张草图,选择原始照片,然后把它们合成在一起,生成新照片(http://www.scriptol.com/design/sketchtophoto.php)。

七、美容算法

自动对容貌进行"美化"的算法(http://www.scriptol.com/programming/algorithm-pretty-face.php)





2018-01-26 06:41:55 AllenHe1 阅读数 850
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    30543 人正在学习 去看看 张中强

图像分割算法研究

2015-10-18 09:58:56 iracer 阅读数 47022
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    30543 人正在学习 去看看 张中强


OpenCV—图像分割中的分水岭算法原理与应用



图像分割是按照一定的原则,将一幅图像分为若干个互不相交的小局域的过程,它是图像处理中最为基础的研究领域之一。目前有很多图像分割方法,其中分水岭算法是一种基于区域的图像分割算法,分水岭算法因实现方便,已经在医疗图像,模式识别等领域得到了广泛的应用。

1.传统分水岭算法基本原理

分水岭比较经典的计算方法是L.Vincent于1991年在PAMI上提出的[1]。传统的分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆地,而集水盆地的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸人水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝如下图所示,即形成分水岭。


传统分水岭算法示意图

然而基于梯度图像的直接分水岭算法容易导致图像的过分割,产生这一现象的原因主要是由于输入的图像存在过多的极小区域而产生许多小的集水盆地,从而导致分割后的图像不能将图像中有意义的区域表示出来。所以必须对分割结果的相似区域进行合并。

[1]L.Vincent, P Soille. Watersheds in digital space: An efficientalgorithms based on immersion simulation[J]. IEEE Trans. on Pattern Analysisand Machine Intelligence, 1991, 13(6): 583-598.

2.改进的分水岭算法基本原理

因为传统分水岭算法存在过分割的不足,OpenCV提供了一种改进的分水岭算法,使用一系列预定义标记来引导图像分割的定义方式。使用OpenCV的分水岭算法cv::wathershed,需要输入一个标记图像,图像的像素值为32位有符号正数(CV_32S类型),每个非零像素代表一个标签。它的原理是对图像中部分像素做标记,表明它的所属区域是已知的。分水岭算法可以根据这个初始标签确定其他像素所属的区域。传统的基于梯度的分水岭算法和改进后基于标记的分水岭算法示意图如下图所示。


传统基于梯度的分水岭算法和基于标记的分水岭算法原理图

从上图可以看出,传统基于梯度的分水岭算法由于局部最小值过多造成分割后的分水岭较多。而基于标记的分水岭算法,水淹过程从预先定义好的标记图像(像素)开始,较好的克服了过度分割的不足。本质上讲,基于标记点的改进算法是利用先验知识来帮助分割的一种方法。因此,改进算法的关键在于如何获得准确的标记图像,即如何将前景物体与背景准确的标记出来。

3.基于标记点的分水岭算法应用

基于标记点的分水岭算法应用步骤

●  封装分水岭算法类

●  获取标记图像

            获取前景像素,并用255标记前景

            获取背景像素,并用128标记背景,未知像素,使用0标记

            合成标记图像

●  将原图和标记图像输入分水岭算法

●  显示结果

(1)封装分水岭算法类

将分水岭算法cv::watershed(image,markers)封装进类WatershedSegmenter,并保存为头文件以便于操作。(本段封装代码参考《OpenCV计算机视觉编程攻略(第二版)》)

#if !defined WATERSHS
#define WATERSHS

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class WatershedSegmenter {

  private:

	  cv::Mat markers;

  public:

	  void setMarkers(const cv::Mat& markerImage) {

		// Convert to image of ints
		markerImage.convertTo(markers,CV_32S);
	  }

	  cv::Mat process(const cv::Mat &image) {

		// Apply watershed
		cv::watershed(image,markers);

		return markers;
	  }

	  // Return result in the form of an image
	  cv::Mat getSegmentation() {
		  
		cv::Mat tmp;
		// all segment with label higher than 255
		// will be assigned value 255
		markers.convertTo(tmp,CV_8U);

		return tmp;
	  }

	  // Return watershed in the form of an image以图像的形式返回分水岭
	  cv::Mat getWatersheds() {
	
		cv::Mat tmp;
		//在变换前,把每个像素p转换为255p+255(在conertTo中实现)
		markers.convertTo(tmp,CV_8U,255,255);

		return tmp;
	  }
};
#endif

(2)获取标记图像

标记前景

读取原图

// Read input image
	cv::Mat image1= cv::imread("image.jpg");
	if (!image1.data)
		return 0; 
// Display the color image
	cv::resize(image1, image1, cv::Size(), 0.7, 0.7);
	cv::namedWindow("Original Image1");
	cv::imshow("Original Image1",image1);

原图

以下代码目的是获取前景物体的像素,并用255标记。这里使用阈值分割初步分割前景和背景,接着使用形态学闭运算连接二值图像中前景的各个部分,并平滑边缘。如何更好的获取前景像素,需要根据实际图像的情况灵活处理。

// Identify image pixels with object
	
	Mat binary;
	cv::cvtColor(image1,binary,COLOR_BGRA2GRAY);
	cv::threshold(binary,binary,30,255,THRESH_BINARY_INV);//阈值分割原图的灰度图,获得二值图像
	// Display the binary image
	cv::namedWindow("binary Image1");
	cv::imshow("binary Image1",binary);
	waitKey();
	
	// CLOSE operation
	cv::Mat element5(5,5,CV_8U,cv::Scalar(1));//5*5正方形,8位uchar型,全1结构元素
	cv::Mat fg1;
	cv::morphologyEx(binary, fg1,cv::MORPH_CLOSE,element5,Point(-1,-1),1);// 闭运算填充物体内细小空洞、连接邻近物体

	// Display the foreground image
	cv::namedWindow("Foreground Image");
	cv::imshow("Foreground Image",fg1);
	waitKey();

阈值分割原图像的灰度图


闭运算获取前景

标记背景和未知区域

在上面阈值分割得到的二值图像binary的基础上,通过对白色前景的深度膨胀运算获得一个超过前景实际大小的物体,紧接着用反向阈值将深度膨胀后的图像中的黑色部分转换成128,即完成了对背景像素的标记。实际上,在0~255范围内,任意不为0或255的值均可作为背景的标记。当然如果有其他类型的物体,可以使用另外一个数值作为其标记。也就是说,多个目标可以有多个标记来帮助分水岭算法正确分割图像。

// Identify image pixels without objects
	
	cv::Mat bg1;
	cv::dilate(binary,bg1,cv::Mat(),cv::Point(-1,-1),4);//膨胀4次,锚点为结构元素中心点
	cv::threshold(bg1,bg1,1,128,cv::THRESH_BINARY_INV);//>=1的像素设置为128(即背景)
	// Display the background image
	cv::namedWindow("Background Image");
	cv::imshow("Background Image",bg1);
	waitKey();

将背景设置为128,未知区域设置为0

合成标记图像

将前景、背景及未知区域合成为一个标记图像。则标记图像中通过255标记前景物体,通过128标记背景,通过0标记未知区域。

//Get markers image

	Mat markers1 = fg1 + bg1; //使用Mat类的重载运算符+来合并图像。
	cv::namedWindow("markers Image");
	cv::imshow("markers Image",markers1);
	waitKey();

标记图像

(3)分水岭算法分割图像

将标记图像和原图输入分水岭算法封装的类WatershedSegmenter,执行分水岭算法,并显示算法运行的结果。
// Apply watershed segmentation

	WatershedSegmenter segmenter1;  //实例化一个分水岭分割方法的对象
	segmenter1.setMarkers(markers1);//设置算法的标记图像,使得水淹过程从这组预先定义好的标记像素开始
	segmenter1.process(image1);     //传入待分割原图
	 
	// Display segmentation result
	cv::namedWindow("Segmentation1");
	cv::imshow("Segmentation1",segmenter1.getSegmentation());//将修改后的标记图markers转换为可显示的8位灰度图并返回分割结果(白色为前景,灰色为背景,0为边缘)
	waitKey();
        // Display watersheds
	cv::namedWindow("Watersheds1");
	cv::imshow("Watersheds1",segmenter1.getWatersheds());//以图像的形式返回分水岭(分割线条)
	waitKey();

代码segmenter1.process(image)将修改标记图像markers,每个值为0的像素都会被赋予一个输入标签,而边缘处的像素赋值为-1,得到的标签图像如下图所示。


显示分水岭分割图像

分水岭分割线显示

(4)显示结果图像

本步骤的目的是将前景物体的分割结果在黑/白底色中显示出来。背景颜色由黑转白时使用了Mat矩阵扫描的.ptr方法与指针运算。

// Get the masked image
	Mat maskimage = segmenter1.getSegmentation();
	cv::threshold(maskimage,maskimage,250,1,THRESH_BINARY);
	cv::cvtColor(maskimage,maskimage,COLOR_GRAY2BGR);

	maskimage = image1.mul(maskimage);
	cv::namedWindow("maskimage");
	cv::imshow("maskimage",maskimage);
	waitKey();

	// Turn background (0) to white (255)
	int nl= maskimage.rows; // number of lines
    int nc= maskimage.cols * maskimage.channels(); // total number of elements per line

    for (int j=0; j<nl; j++) {
         uchar* data= maskimage.ptr<uchar>(j);
		for (int i=0; i<nc; i++) 
		{
            // process each pixel ---------------------
			if (*data==0) //将背景由黑色改为白色显示
				*data=255;
			data++;//指针操作:如为uchar型指针则移动1个字节,即移动到下1列
        }
     }
	cv::namedWindow("result");
	cv::imshow("result",maskimage);
	waitKey();

原图的前景分割图(黑色背景)


原图的前景分割图(白色背景)

从上图的分割结果可以看出,基于标记图像的分水岭算法较好的实现了复杂背景下前景目标分割。算法应用的关键步骤为标记图像的获取,目前很多文献提出了各类获取标记图像的方法,如何使用还需要根据所处理的图像来量身确定。

贴出实验原始图像:)

转载请注明:iracer的CSDN博客 http://blog.csdn.net/iracer/article/details/49225823

0

2016-05-09 20:38:07 horseinch 阅读数 7023
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    30543 人正在学习 去看看 张中强

刚开始想把这部分内容命名为“基本算法”,意在介绍图像处理中的一些基本算法,后来仔细想想决定不这么写,因为图像处理是一个非常大的概念,图像处理不等于人脸识别,也不等于模式识别,直接介绍诸如图像处理基本算法之类的内容很容易写成空话,没有什么实际意义。读者有兴趣的话可以直接谷歌百度“图像处理十大经典算法”,上面有我想说的内容。

万变不离其宗,算法是死的,重在思想。举个例子,我个人是主攻模式识别方向,在这个方向判断一个学生是否入门有一个非常简单的方法,就是“如果你能把图像很自然的想象成高维空间中的一个点”,那就说明在模式识别方面入门了,可以对图像进行分类了。

当然标准不是唯一,在其他领域如目标检测也会有其他的判断标准,总之我们要对图像进行处理,那么图像就不再只是图像,它可能会演变成各种不同形式的概念,可能是点,可能是面,还可能是一个坐标空间。在目标跟踪的经典算法粒子滤波中,将一个个的小图像块看做一个个粒子;在子空间理论中,将一系列图像放在一起构建一个成分主空间(例如主成分分析PCA算法等等。,我不会详细介绍这些算法,说多了就显得抽象老套,但我要说的是我们一定要把图像本身理解好,它是一个图像,是一个矩阵,是一个信息的容器,是一种数据的表现形式,图像不一定都必须在视觉上有意义(比如频域的图像)。

总之图像处理的基本思想还是要立足于图像本身,要深度到图像内部结构中,思维要灵活。我当时做本科毕设时,怎么也不知道图像和高维空间中的点之间有什么对应关系,后来总算有一天,突然就明白了,这也就是所谓的量变产生质变。总之一定要多想,多总结,主动去钻研,才能够真正领悟一些东西。最基本的东西往往蕴藏着深奥的道理,无论你现在多牛多厉害,都不能放掉最本源的东西。多想想图像是什么,有什么本质属性,你可能无法得到准确的答案,但肯定能得到一些有用的感悟(有点像哲学问题了)。


算法研究
算法研究应该是图像处理的核心工作,尤其是各大高校的博士硕士。这里我并不想谈那些高大上的算法,我更想说的是一些算法研究的一些基础的东西,比如说一些基础课程,比如说矩阵运算。

研究图像处理的算法,离不开数学。在这里我建议图像处理方面的硕士一定要上两门课:《泛函分析》以及《最优化算法》,有的学校已经将这两门课列为了研究生阶段的必修课程。这两门可可以说是图像处理(至少是模式识别)的基础。我当初没上过最优化算法,但后来也自己补上了,不然真的是寸步难行。至于泛函我当时听课的时候也不是很懂,但是在之后的研究过程中发现很多图像处理的基本知识基本理论都和泛函分析中枯燥的定理如出一辙,没办法,有的东西本身就是枯燥的干货,学着费力,缺它不行。

  其次我想说的是矩阵运算。图像就是矩阵,图像处理就是矩阵运算。大家为什么都喜欢用Matlab,就是因为它的矩阵运算能力实在是太强大,在Matlab的世界中任何变量都是矩阵。同样OpenCv之所以能流行,不仅仅是因为它良好的封装性,也是因为它的矩阵格式,它定义了Mat基础类,允许你对矩阵进行各种操作。Python也不例外,它的Numpy就是一个专门的线性代数库。

  真正在图像编程过程中,那些看着高大上的API函数归根到底都是工具,查查手册就能找到,真正核心还是在算法,算法是由公式编写的,公式的单元是变量,而图像届的变量就是矩阵。所以,熟练去操作矩阵,求秩、求逆、最小二乘,求协方差,都是家常便饭。所以,如果你有幸能上《矩阵分析》这门课,一定要把它看懂,那里面都是干货。

2018-10-30 22:19:36 Eastmount 阅读数 5825
  • Java经典算法讲解

    在面试中,算法题目是必须的,通过算法能够看出一个程序员的编程思维,考察对复杂问题的设计与分析能力,对问题的严谨性都能够体现出来。一个算法的好坏,直接影响一个方法调用的性能,进而影响软件的整体性能。算法是学习所有编程语言的基础,在Java的学习过程中首先也会选择以算法起步,本次课程重点讲解Java开发中常用的基本算法。

    30543 人正在学习 去看看 张中强

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~

该系列在github所有源代码:https://github.com/eastmountyxz/ImageProcessing-Python
PS:请求帮忙点个Star,哈哈,第一次使用Github,以后会分享更多代码,一起加油。

同时推荐作者的C++图像系列知识:
[数字图像处理] 一.MFC详解显示BMP格式图片
[数字图像处理] 二.MFC单文档分割窗口显示图片
[数字图像处理] 三.MFC实现图像灰度、采样和量化功能详解
[数字图像处理] 四.MFC对话框绘制灰度直方图
[数字图像处理] 五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理详解
[数字图像处理] 六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解
[数字图像处理] 七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解

前文参考:
[Python图像处理] 一.图像处理基础知识及OpenCV入门函数
[Python图像处理] 二.OpenCV+Numpy库读取与修改像素
[Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理
[Python图像处理] 四.图像平滑之均值滤波、方框滤波、高斯滤波及中值滤波
[Python图像处理] 五.图像融合、加法运算及图像类型转换
[Python图像处理] 六.图像缩放、图像旋转、图像翻转与图像平移

本篇文章主要讲解Python调用OpenCV实现图像阈值化处理操作,包括二进制阈值化、反二进制阈值化、截断阈值化、反阈值化为0、阈值化为0。全文均是基础知识,希望对您有所帮助。
1.阈值化
2.二进制阈值化
3.反二进制阈值化
4.截断阈值化
5.反阈值化为0
6.阈值化为0

PS:文章参考自己以前系列图像处理文章及OpenCV库函数,同时部分参考网易云视频,推荐大家去学习。同时,本篇文章涉及到《计算机图形学》基础知识,请大家下来补充。

PSS:2019年1~2月作者参加了CSDN2018年博客评选,希望您能投出宝贵的一票。我是59号,Eastmount,杨秀璋。投票地址:https://bss.csdn.net/m/topic/blog_star2018/index

五年来写了314篇博客,12个专栏,是真的热爱分享,热爱CSDN这个平台,也想帮助更多的人,专栏包括Python、数据挖掘、网络爬虫、图像处理、C#、Android等。现在也当了两年老师,更是觉得有义务教好每一个学生,让贵州学子好好写点代码,学点技术,"师者,传到授业解惑也",提前祝大家新年快乐。2019我们携手共进,为爱而生。

一. 阈值化

(注:该部分参考作者的论文《基于苗族服饰的图像锐化和边缘提取技术研究》)

图像的二值化或阈值化(Binarization)旨在提取图像中的目标物体,将背景以及噪声区分开来。通常会设定一个阈值T,通过T将图像的像素划分为两类:大于T的像素群和小于T的像素群。
灰度转换处理后的图像中,每个像素都只有一个灰度值,其大小表示明暗程度。二值化处理可以将图像中的像素划分为两类颜色,常用的二值化算法如公式1所示:

{Y=0gray<TY=255gray>=T\begin{cases} Y=0,gray<T\\ Y=255,gray>=T\\ \end{cases}
当灰度Gray小于阈值T时,其像素设置为0,表示黑色;当灰度Gray大于或等于阈值T时,其Y值为255,表示白色。
Python OpenCV中提供了阈值函数threshold()实现二值化处理,其公式及参数如下图所示:
retval, dst = cv2.threshold(src, thresh, maxval, type)

常用的方法如下表所示,其中函数中的参数Gray表示灰度图,参数127表示对像素值进行分类的阈值,参数255表示像素值高于阈值时应该被赋予的新像素值,最后一个参数对应不同的阈值处理方法。
对应OpenCV提供的五张图如下所示,第一张为原图,后面依次为:二进制阈值化、反二进制阈值化、截断阈值化、反阈值化为0、阈值化为0。
二值化处理广泛应用于各行各业,比如生物学中的细胞图分割、交通领域的车牌设别等。在文化应用领域中,通过二值化处理将所需民族文物图像转换为黑白两色图,从而为后面的图像识别提供更好的支撑作用。下图表示图像经过各种二值化处理算法后的结果,其中“BINARY”是最常见的黑白两色处理。


二. 二进制阈值化

该方法先要选定一个特定的阈值量,比如127。新的阈值产生规则如下:
dst(x,y)={maxValifsrc(x,y)>thresh0otherwise dst(x,y) = \begin{cases} maxVal, if src(x,y)>thresh\\ 0,otherwise\\ \end{cases}
(1) 大于等于127的像素点的灰度值设定为最大值(如8位灰度值最大为255)
(2) 灰度值小于127的像素点的灰度值设定为0
例如,163->255,86->0,102->0,201->255。

关键字为 cv2.THRESH_BINARY,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#二进制阈值化处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_BINARY)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出为两个返回值,r为127,b为处理结果(大于127设置为255,小于设置为0)。如下图所示:



三. 反二进制阈值化

该方法与二进制阈值化方法相似,先要选定一个特定的灰度值作为阈值,比如127。新的阈值产生规则如下:
dst(x,y)={0ifsrc(x,y)>threshmaxValotherwise dst(x,y) = \begin{cases} 0, if src(x,y)>thresh\\ maxVal,otherwise\\ \end{cases}
(1) 大于127的像素点的灰度值设定为0(以8位灰度图为例)
(2) 小于该阈值的灰度值设定为255
例如,163->0,86->255,102->255,201->0。

关键字为 cv2.THRESH_BINARY_INV,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#反二进制阈值化处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_BINARY_INV)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:

该方法得到的结果正好与二进制阈值化方法相反,亮色元素反而处理为黑色,暗色处理为白色。

四. 截断阈值化

该方法需要选定一个阈值,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变,比如127。新的阈值产生规则如下:
dst(x,y)={thresholdifsrc(x,y)>threshsrc(x,y)otherwise dst(x,y) = \begin{cases} threshold, if src(x,y)>thresh\\ src(x,y),otherwise\\ \end{cases}
(1) 大于等于127的像素点的灰度值设定为该阈值127
(2) 小于该阈值的灰度值不改变
例如,163->127,86->86,102->102,201->127。

关键字为 cv2.THRESH_TRUNC,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#截断阈值化处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TRUNC)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示::

该处理方法相当于把图像中比较亮(大于127,偏向于白色)的像素值处理为阈值。

五. 反阈值化为0

该方法先选定一个阈值,比如127,接着对图像的灰度值进行如下处理:
dst(x,y)={0ifsrc(x,y)>threshsrc(x,y)otherwise dst(x,y) = \begin{cases} 0, if src(x,y)>thresh\\ src(x,y),otherwise\\ \end{cases}
(1) 大于等于阈值127的像素点变为0
(2) 小于该阈值的像素点值保持不变
例如,163->0,86->86,102->102,201->0。

关键字为 cv2.THRESH_TOZERO_INV,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#反阈值化为0处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TOZERO_INV)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:



六. 阈值化为0

该方法先选定一个阈值,比如127,接着对图像的灰度值进行如下处理:
dst(x,y)={src(x,y)ifsrc(x,y)>thresh0otherwise dst(x,y) = \begin{cases} src(x,y), if src(x,y)>thresh\\ 0,otherwise\\ \end{cases}
(1) 大于等于阈值127的像素点,值保持不变
(2) 小于该阈值的像素点值设置为0
例如,163->163,86->0,102->0,201->201。

关键字为 cv2.THRESH_TOZERO,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#阈值化为0处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TOZERO)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:

该算法把比较亮的部分不变,比较暗的部分处理为0。

完整五个算法的对比代码如下所示:

#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt

#读取图像
img=cv2.imread('test.jpg')
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  

#阈值化处理
ret,thresh1=cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY)  
ret,thresh2=cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY_INV)  
ret,thresh3=cv2.threshold(GrayImage,127,255,cv2.THRESH_TRUNC)  
ret,thresh4=cv2.threshold(GrayImage,127,255,cv2.THRESH_TOZERO)  
ret,thresh5=cv2.threshold(GrayImage,127,255,cv2.THRESH_TOZERO_INV)

#显示结果
titles = ['Gray Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']  
images = [GrayImage, thresh1, thresh2, thresh3, thresh4, thresh5]  
for i in xrange(6):  
   plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()

输出结果如下图所示:

希望文章对大家有所帮助,如果有错误或不足之处,还请海涵。最近经历的事情太多,有喜有悲,关闭了朋友圈,希望通过不断学习和写文章来忘记烦劳,将忧郁转换为动力。哎,总感觉自己在感动这个世界,帮助所有人,而自己却…谁有关心秀璋?晚安。
(By:Eastmount 2018-10-30 晚上10点 https://blog.csdn.net/Eastmount/)

没有更多推荐了,返回首页