2016-06-29 22:26:53 lpsl1882 阅读数 11278

参考并编辑:
http://blog.csdn.net/wangjinwj2008/article/details/8272081
http://blog.csdn.net/skyereeee/article/details/7265415
http://blog.csdn.net/carson2005/article/details/7200440

CIE色度图:CIE(Commission Internationale de L’Eclairage):国际照明委员会,根据其法语名称简写为CIE。其前身是1900年成立的国际光度委员会(International Photometric Commission;IPC),1913年改为现名。总部设在奥地利维也纳。CIE制订了一系列色度学标准,一直沿用到数字视频时代,其中包括白光标准(D65)和阴极射线管(CRT)内表面红、绿、蓝三种磷光理论上的理想颜色。
这里写图片描述
在色度图上绘制一个三角区域,只要显示器能正常显示三角区域顶点上的颜色,那么三角区域内部的颜色都可以由三个顶点颜色组成,但是外部颜色却不行。也就是说如果显示器给出了可以显示的三角顶点颜色,那么该设备只能够显示三角范围内部的颜色。很多显示设备都会提供其显示色度范围,理论上色度范围越大显示效果越好。

LAB色域:其包括自然界中可见光谱的颜色,它所组成的色域空间最大,包含了人眼所能见到的所有颜色。同RGB颜色空间相比,Lab是一种不常用的色彩空间。它是在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。1976年,经修改后被正式命名为CIELab。它是一种设备无关的颜色系统,也是一种基于生理特征的颜色系统。这也就意味着,它是用数字化的方法来描述人的视觉感应。Lab颜色空间中的L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;a表示从红色到绿色的范围,取值范围是[127,-128];b表示从黄色到蓝色的范围,取值范围是[127,-128]。需要提醒的是,Lab颜色空间比计算机显示器、打印机甚至比人类视觉的色域都要大,表示为 Lab 的位图比 RGB 或 CMYK 位图获得同样的精度要求更多的每像素数据。虽然我们在生活中使用RGB颜色空间更多一些,但也并非Lab颜色空间真的一无所有。例如,在 Adobe Photoshop图像处理软件中,TIFF格式文件中,PDF文档中,都可以见到Lab颜色空间的身影。而在计算机视觉中,尤其是颜色识别相关的算法设计中,rgb,hsv,lab颜色空间混用更是常用的方法。
这里写图片描述

Adobe RGB色域:Adobe RGB是Adobe Red GreenBlue的缩写,是由开发专业图像处理软件Photoshop而闻名的Adobe公司所设定的色彩空间标准,它拥有比sRGB更宽广的色彩空间和优秀的色彩层次体现,且可以完全覆盖印刷所需的CMYK色彩空间,因此,它在印刷、高精度打印这样的专业领域,占据了绝对的主导地位。它占LAB色域的50%左右,是作为专业摄影领域中的首选,只有极少昂贵的显示器才能满足它的需求,而这些显示器通常运用于专业设计和出版印刷领域。但Adobe RGB由于与显示器、投影仪等输出设备的匹配,以及网络显示软件方面的兼容等问题,在我们日常与他人进行图片欣赏交流时,会显得色彩黯淡、图像反差弱。这是由于大多数人的显示器和软件只支持sRGB色彩空间,而宽广的Adobe RGB无法施展其优势,反而被它们解读成暗淡无光的效果。

sRGB色域:它占LAB色域的35%左右,是普通显示器的色彩标准。sRGB是standard Red Green Blue的缩写,其含义为标准色彩空间。它是由惠普公司和微软公司年于1997年共同开发的,由于sRGB色彩空间的色域与当时CRT显示器的色彩显示基本吻合(也与目前绝大多数的液晶显示sRGB色彩空间广泛用于网络展示和扩印照片器相当),且这两家公司的在市场的实力和产品占有率,因此它被广泛地运用于网络展示、保存和民用照片打印、冲印领域。但由于sRGB色域空间小,所以它所能包含的细微的色彩差别就很少。所以,尽管我们看到sRGB图片的色彩饱和度可以很高,但色彩的层次过渡明显不足。因此在印刷时,将sRGB转为CMYK会显得图像干瘪,层次明显不足。
这里写图片描述

CMYK色域:是专门用于印刷的色彩空间,它完全包含于AdobeRGB色域中,但其与sRGB空间有交集也有差异。CMYK(cyan,magenta,yellow)颜色空间应用于印刷工业,印刷业通过青(C)、品(M)、黄(Y)三原色油墨的不同 网点面积率的叠印来表现丰富多彩的颜色和阶调,这便是三原色的CMY颜色空间。实际印刷中,一般采用青 (C)、品(M)、黄(Y)、黑(BK)四色印刷,在印刷的中间调至暗调增加黑版。当红绿蓝三原色被混合时,会产生 白色,但是当混合蓝绿色、紫红色和黄色三原色时会产生黑色。既然实际用的墨水并不会产生纯正的颜色, 黑色是包括在分开的颜色,而这模型称之为CMYK。CMYK颜色空间是和设备或者是印刷过程相关的,则工艺方法、 油墨的特性、纸张的特性等,不同的条件有不同的印刷结果。所以CMYK颜色空间称为与设备有关的表色空间。 而且,CMYK具有多值性,也就是说对同一种具有相同绝对色度的颜色,在相同的印刷过程前提下,可以用分种 CMYK数字组合来表示和印刷出来。这种特性给颜色管理带来了很多麻烦,同样也给控制带来了很多的灵活性。 在印刷过程中,必然要经过一个分色的过程,所谓分色就是将计算机中使 用的RGB颜色转换成印刷使用的CMYK 颜色。在转换过程中存在着两个复杂的问题,其一是这两个颜色空间在表现颜色的范围上不完全一样,RGB的 色域较大而CMYK则较小,因此就要进行色域压缩;其二是这两个颜色都是和具体的设备相关的,颜色本身没有 绝对性。因此就需要通过一个与设备无关的颜色空间来进行转换,即可以通过以上介绍的XYZ或LAB色空间来 进行转换。
这里写图片描述

HSV颜色空间:HSV(hue,saturation,value)颜色空间的模型对应于圆柱坐标系中的一个圆锥形子集,圆锥的顶面对应于V=1. 它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮。色彩H由绕V轴的旋转角给定。红色对应于 角度0° ,绿色对应于角度120°,蓝色对应于角度240°。在HSV颜色模型中,每一种颜色和它的补色相差180° 。 饱和度S取值从0到1,所以圆锥顶面的半径为1。HSV颜色模型所代表的颜色域是CIE色度图的一个子集,这个 模型中饱和度为百分之百的颜色,其纯度一般小于百分之百。在圆锥的顶点(即原点)处,V=0,H和S无定义, 代表黑色。圆锥的顶面中心处S=0,V=1,H无定义,代表白色。从该点到原点代表亮度渐暗的灰色,即具有不同 灰度的灰色。对于这些点,S=0,H的值无定义。可以说,HSV模型中的V轴对应于RGB颜色空间中的主对角线。 在圆锥顶面的圆周上的颜色,V=1,S=1,这种颜色是纯色。HSV模型对应于画家配色的方法。画家用改变色浓和 色深的方法从某种纯色获得不同色调的颜色,在一种纯色中加入白色以改变色浓,加入黑色以改变色深,同时 加入不同比例的白色,黑色即可获得各种不同的色调。
这里写图片描述

HSI颜色空间:HSI色彩空间是从人的视觉系统出发,用色调(Hue)、色饱和度(Saturation或Chroma)和亮度 (Intensity或Brightness)来描述色彩。HSI色彩空间可以用一个圆锥空间模型来描述。用这种 描述HIS色彩空间的圆锥模型相当复杂,但确能把色调、亮度和色饱和度的变化情形表现得很清楚。 通常把色调和饱和度通称为色度,用来表示颜色的类别与深浅程度。由于人的视觉对亮度的敏感 程度远强于对颜色浓淡的敏感程度,为了便于色彩处理和识别,人的视觉系统经常采用HSI色彩空间, 它比RGB色彩空间更符合人的视觉特性。在图像处理和计算机视觉中大量算法都可在HSI色彩空间中 方便地使用,它们可以分开处理而且是相互独立的。因此,在HSI色彩空间可以大大简化图像分析 和处理的工作量。HSI色彩空间和RGB色彩空间只是同一物理量的不同表示法,因而它们之间存在着 转换关系。
- 色相 (Hue):指物体传导或反射的波长。更常见的是以颜色如红色,橘色或绿色来辨识,取 0 到 360 度的数值来衡量。
- 饱和度 (Saturation):又称色度,是指色彩的强度或纯度。饱和度代表灰色与色调的比例,并以 0% (灰色) 到 100% (完全饱和) 来衡量。
- 亮度 (Intensity):是指颜色的相对明暗度,通常以 0% (黑色) 到 100% (白色) 的百分比来衡量。
这里写图片描述

Ycc颜色空间:柯达发明的颜色空间,由于PhotoCd在存储图像的时候要经过一种模式压缩,所以 PhotoCd采用了 Ycc颜色空间,Ycc空间将亮度作由它的主要组件,具有两个 单独的颜色通道,采用Ycc颜色空间 来保存图像,可以节约存储空间。

YUV颜色空间:在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD(点耦合器件)摄像机,它把摄得的彩色图像 信号,经分色、分别放大校正得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y、B-Y, 最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这就是我们常用的YUV色彩空间。 采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量, 那么这样表示的图就是黑白灰度图。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机 的兼容问题,使黑白电视机也能接收彩色信号。根据美国国家电视制式委员会,NTSC制式的标准,当白光的 亮度用Y来表示时,它和红、绿、蓝三色光的关系可用如下式的方程描述:Y=0.3R+0.59G+0.11B 这就是常用 的亮度公式。色差U、V是由B-Y、R-Y按不同比例压缩而成的。如果要由YUV空间转化成RGB空间,只要进行 相反的逆运算即可。与YUV色彩空间类似的还有Lab色彩空间,它也是用亮度和色差来描述色彩分量,其中L为 亮度、a和b分别为各色差分量。

XYZ颜色空间:国际照明委员会(CIE)在进行了大量正常人视觉测量和统计,1931年建立了”标准色度观察者”, 从而奠定了现代CIE标准色度学的定量基础。由于”标准色度观察者”用来标定光谱色时出现负 刺激值,计算不便,也不易理解,因此1931年CIE在RGB系统基础上,改用三个假想的原色X、Y、 Z建立了一个新的色度系统。将它匹配等能光谱的三刺激值,定名为”CIE1931 标准色度观察者光谱三刺激值”,简称为”CIE1931标准色度观察者”。这一系统叫做”CIE1931标准色度系统”或称为” 2° 视场XYZ色度系统”。CIEXYZ颜色空间稍加变换就可得到Yxy色彩空间,其中Y取三刺激值中Y的值,表示亮度,x、y反映颜色的色度特性。定义如下:在色彩管理中,选择与设备无关的颜色空间是十分重要的,与设备无关的颜色空间由国际照明委员会(CIE)制定,包括CIEXYZ和CIELAB两个标准。它们包含了人眼所能辨别的全部颜色。而且,CIEYxy测色制的建立给定量的确定颜色创造了条件。但是,在这一空间中,两种不同颜色之间的距离值并不能正确地反映人们色彩感觉差别的大小,也就是说在CIEYxy色厦图中,在不同的位置不同方向上颜色的宽容量是不同的,这就是Yxy颜色空间 的不均匀性。这一缺陷的存在,使得在Yxy及XYZ空间不能直观地评价颜色。

RGB颜色空间:RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
这里写图片描述

2019-02-11 10:24:46 limiyudianzi 阅读数 805

最为大家熟悉的色彩空间就是rgb色彩空间和灰度色彩空间了,除此之外HSV,YCbCr也都各有应用。这里我们就简单的介绍一下色彩空间变化,这就涉及到python中skimag.color的应用

首先skimage支持的色彩空间有:
[‘rgb’, ‘hsv’, ‘rgb cie’, ‘xyz’, ‘yuv’, ‘yiq’, ‘ypbpr’, ‘ycbcr’, ‘ydbdr’]
常用的操作有

# 转换色彩空间通用的方法
# arr是要转换的图片,fromspace是arr图片的色彩空间,
# tospace是要转换成为的色彩空间。
skimage.color.convert_colorspace(arr, fromspace, tospace)

#除此之外还有很多简短的方便的函数比如:
Skimage.color.rgb2gray(rgb)
Skimage.color.gray2rgb(gray)
Skimage.color.hsv2rgb(hsv)
Skimage.color.rgb2hsv(rgb)

下面我们就展示一个宇航员图片的例子,需要综合用到上一讲所涉及到的示例图片的读取,显示,以及显示图像的属性等知识。

import skimage
img = skimage.data.astronaut() #读取图片
skimage.io.imshow(img)
skimage.io.show()

img_gray = skimage.color.rgb2gray(img) #灰度图
skimage.io.imshow(img_gray)
skimage.io.show()

img_hsv = skimage.color.rgb2hsv(img) #hsv空间
skimage.io.imshow(img_hsv)
skimage.io.show()

在这里插入图片描述

上面是其对应的显示结果和属性,这里有一个坑就是变成了灰度图之后,整个图像会被归一化,还需要手动变成我们熟悉的0到255的强度,同时hsv空间的三个通道分别是色调H,饱和度S和明度V,色调是0到360度,其他两个都是0到1,这里变成hsv空间之后色调好像也被归一化了。之所以显示的这么魔性是因为数据的存储都是使用的numpy数据格式,并没有指明是什么色彩空间之类的,所以在imshow的时候应该就直接被当做了归一化的RGB图像进行显示了。

更多skimage教程请看这里

2019-01-09 21:23:55 weixin_36049506 阅读数 275


注:本文使用opencv3.4.2

灰度色彩空间

单通道,取值范围[0,255]

RGB色彩空间(opencv中习惯用BGR)

计算机色彩显示器和彩色电视机显示色彩的原理一样,都是采用R、G、B相加混色的原理,通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示。
在RGB颜色空间中,任意色光F都可以用R、G、B三色不同分量的相加混合而成:F=r[R]+r[G]+r[B] F=r[R]+r[G]+r[B]
RGB色彩空间还可以用一个三维的立方体来描述。当三基色分量都为0(最弱)时混合为黑色光;当三基色都为k(最大,值由存储空间决定)时混合为白色光。

opencv中R,G,B三通道取值范围均为[0,255]。

在这里插入图片描述

HSV/HSL色彩空间

HSV是一种将RGB色彩空间中的点在倒圆锥体中的表示方法。HSV即色相(Hue)、饱和度(Saturation)、明度(Value),又称HSB(B即Brightness)。色相是色彩的基本属性,就是平常说的颜色的名称,如红色、黄色等。饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。明度(V),取0-max(计算机中HSV取值范围和存储的长度有关)。HSV颜色空间可以用一个圆锥空间模型来描述。圆锥的顶点处,V=0,H和S无定义,代表黑色。圆锥的顶面中心处V=max,S=0,H无定义,代表白色。

还有一种圆柱形表示
在这里插入图片描述
HSL和HSV稍有区别,一般我们常用的是HSV模型:
https://blog.csdn.net/binglan520/article/details/56288135

Hue 定义在圆周上,取值范围[0,360][0,360]
S和V取值范围是[0,1][0,1]

opencv中:

  • 图片数据类型为uchar(CV_8U)和ushort(CV_16U)时,默认将Hue映射到[0,180][0,180],区间[180,255][180,255]和区间[0,75][0,75]重合,此时可以修改fullRangetrue将Hue映射到[0,256][0,256],但是我们一般不这样做。
  • 图片类型为float(CV_32F)时,将Hue映射到[0,360][0,360]
  • S和V取值范围是[0,255][0,255]

opencv源码:

int hrange = depth == CV_32F ? 360 : isFullRange ? 256 : 180;

CIE-Lab色彩空间

占坑

opencv中的存储

c++ 中,R,G和B通道值的常规范围是:

  • CV_8U图像为0到255
  • 对于CV_16U图像,为0到65535
  • CV_32F图像为0到1

色彩空间转换

使用void cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )函数。

  • src,dst,code,dcn:原图片,目标图片,转换格式,目标图片通道数。

这部分代码位于opencv_imgproc项目的color.cpp中,需要源码编译才能查看(源码编译步骤:https://blog.csdn.net/qq_33485434/article/details/78488710):
在这里插入图片描述

下面是cvtColor的主要代码,篇幅过长,没有全放上来。

void cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
{
    CV_INSTRUMENT_REGION()
    if(dcn <= 0) //如果dcn错误,通过code获得正确的dcn
            dcn = dstChannels(code);
//这部分涉及UMat(需要opencl,能够使用gpu计算),调用的是ocl_cvtColor()函数
    CV_OCL_RUN( _src.dims() <= 2 && _dst.isUMat() &&
                !(CV_MAT_DEPTH(_src.type()) == CV_8U && (code == COLOR_Luv2BGR || code == COLOR_Luv2RGB)),
                ocl_cvtColor(_src, _dst, code, dcn) )

//代码主要部分,通过switch函数将不同的转换分成不同任务
    switch( code )
    {
        case COLOR_BGR2GRAY: case COLOR_BGRA2GRAY:
        case COLOR_RGB2GRAY: case COLOR_RGBA2GRAY:
            cvtColorBGR2Gray(_src, _dst, swapBlue(code));
            break;

        case COLOR_GRAY2BGR:
        case COLOR_GRAY2BGRA:
            cvtColorGray2BGR(_src, _dst, dcn);
            break;
        
        case COLOR_BGR2HSV: case COLOR_BGR2HSV_FULL:
        case COLOR_RGB2HSV: case COLOR_RGB2HSV_FULL:
            cvtColorBGR2HSV(_src, _dst, swapBlue(code), isFullRangeHSV(code));
            break;

        case COLOR_HSV2BGR: case COLOR_HSV2BGR_FULL:
        case COLOR_HSV2RGB: case COLOR_HSV2RGB_FULL:
            cvtColorHSV2BGR(_src, _dst, dcn, swapBlue(code), isFullRangeHSV(code));
            break;
			...
} 

BGR空间到灰度空间

理论公式:
RGB[A] to Gray:Y0.299R+0.587G+0.114B RGB[A]\ to\ Gray:Y←0.299⋅R+0.587⋅G+0.114⋅B
从公式上可以看出,绿色通道占主要部分。
opencv源码:

void cvtColorBGR2Gray( InputArray _src, OutputArray _dst, bool swapb)
{
	//CvtHelper是一个opencv自定义类型,定义在Color.hpp中,
	//CvtHelper(InputArray _src, OutputArray _dst, int dcn)
	//功能是:
	//1.验证一下src和dst的数据类型,通道数是否支持;
	//2.判断src和dst是否相同。如果src和dst相同,先对src进行copy,操作完再用copy的img覆盖src
	//3.涉及到yuv空间有一个尺寸上的变换
	//4.把处理后的image赋给自身的成员
    CvtHelper< Set<3, 4>, Set<1>, Set<CV_8U, CV_16U, CV_32F> > h(_src, _dst, 1);
	//调用cvtBGRtoGray
    hal::cvtBGRtoGray(h.src.data, h.src.step, h.dst.data, h.dst.step, h.src.cols, h.src.rows,
                      h.depth, h.scn, swapb);
}
// 支持三种数据类型:8u, 16u, 32f
void cvtBGRtoGray(const uchar * src_data, size_t src_step,
                  uchar * dst_data, size_t dst_step,
                  int width, int height,
                  int depth, int scn, bool swapBlue)
{
    CV_INSTRUMENT_REGION()
	//涉及 OpenCV Hardware Acceleration Layer (HAL),不去管它
    CALL_HAL(cvtBGRtoGray, cv_hal_cvtBGRtoGray, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue);

	//检查是否支持intel的ipp库,就是那个讨厌的ippicv,这部分我去掉了
	...
	
    int blueIdx = swapBlue ? 2 : 0;
    if( depth == CV_8U )
    	//核心代码用CvtColorLoop调用RGB2Gray
    	//CvtColorLoop里边:
    	//1.并行处理RGB2Gray每次传入一个pixel,共调用n=width*height次
    	//2.对像素归一化,像素映射到[0,1]
        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Gray<uchar>(scn, blueIdx, 0));
    else if( depth == CV_16U )
        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Gray<ushort>(scn, blueIdx, 0));
    else
        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Gray<float>(scn, blueIdx, 0));
}

    	/*
    	color.hpp中R2Y, G2Y, B2Y等定义
    	//constants for conversion from/to RGB and Gray, YUV, YCrCb according to BT.601
    	const float B2YF = 0.114f;
    	const float G2YF = 0.587f;
    	const float R2YF = 0.299f;

    	enum
    	{
        	yuv_shift = 14,
        	xyz_shift = 12,
        	R2Y = 4899, // == R2YF*16384
        	G2Y = 9617, // == G2YF*16384
        	B2Y = 1868, // == B2YF*16384
        	BLOCK_SIZE = 256
    	};
		*/

template<typename _Tp> struct RGB2Gray
{
    typedef _Tp channel_type;
	//RGB2Gray参数
	//_srccn:原图片通道数
	//蓝色通道index,决定是否对通道转换,BGR=0,RGB=2,BGR和RGB就差在这了
	//coeffs:各通道权重
    RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
    {
    	//0.299f, 0.587f, 0.114f
        static const float coeffs0[] = { R2YF, G2YF, B2YF };
        memcpy( coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]) );
        if(blueIdx == 0)
            std::swap(coeffs[0], coeffs[2]);
    }

    void operator()(const _Tp* src, _Tp* dst, int n) const
    {
        int scn = srccn;
        float cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
        for(int i = 0; i < n; i++, src += scn)
        	//核心代码!!! 
        	//// 0.299f*src[0]+0.587f*src[1]+0.114f*src[2]
            dst[i] = saturate_cast<_Tp>(src[0]*cb + src[1]*cg + src[2]*cr);
    }
    int srccn;
    float coeffs[3];
};

其它转换方法:
https://www.cnblogs.com/zhangjiansheng/p/6925722.html

灰度空间到BGR空间

由于灰度空间到BGR空间的转换进行了升维,我们并不知道B、G、R三个通道所占的概率,所以认为是等概率的,此外,如果有alpha通道,直接设为最大值。公式如下:
Gray to RGB[A]:RY,GY,BY,Amax(ChannelRange) Gray\ to\ RGB[A]:R←Y,G←Y,B←Y,A←max(ChannelRange)

前面的通道数、尺寸、数据类型检查、封装、并行加速等和上面类似,直接放核心代码:

template<typename _Tp>
struct Gray2RGB
{
    typedef _Tp channel_type;

    Gray2RGB(int _dstcn) : dstcn(_dstcn) {}
    void operator()(const _Tp* src, _Tp* dst, int n) const
    {
        if( dstcn == 3 )
            for( int i = 0; i < n; i++, dst += 3 )
            {
                dst[0] = dst[1] = dst[2] = src[i];
            }
        else
        {
            _Tp alpha = ColorChannel<_Tp>::max();
            for( int i = 0; i < n; i++, dst += 4 )
            {
                dst[0] = dst[1] = dst[2] = src[i];
                dst[3] = alpha;
            }
        }
    }

    int dstcn;
};

实验:将彩色图转为灰度图再转回彩色图

int main()
{

	Mat img = imread("dog.jpg");
	resize(img, img, Size(img.cols / 2,img.rows / 2));//长、宽缩小一倍
	Mat grayimg,newimg;
	cvtColor(img, grayimg, COLOR_BGR2GRAY); 
	cvtColor(grayimg, newimg, COLOR_GRAY2BGR);
	
	imshow("origin", img);
	imshow("gray img", grayimg);
	imshow("new img", newimg);

	waitKey(0);
	destroyAllWindows();
}

在这里插入图片描述
可以看出灰度图转无法真正的转为彩色图。因为并不知道RGB与灰度的比例关系,只能简单地设每个像素的 R=G=B=灰度。转换之后,图片看上去还是灰色。

BGR空间与HSV空间相互转换

直接上官网的截图了:
在这里插入图片描述
在这里插入图片描述
opencv源码:
rgb转hsv,uchar或ushort型的类RGB2HSV_b
float型的RGB2HSV_f和它很相似,就不放了。

struct RGB2HSV_b
{
    typedef uchar channel_type;
	//构造函数,初始化列表为:
	//source image 通道数
	//蓝色分量所在通道的index  BGR是0,RGB是2
    //h通道范围 180或256
    RGB2HSV_b(int _srccn, int _blueIdx, int _hrange)
    : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange)
    {
    //断言,判断h通道范围是否正确
        CV_Assert( hrange == 180 || hrange == 256 );
    }

    void operator()(const uchar* src, uchar* dst, int n) const
    {
        int i, bidx = blueIdx, scn = srccn;
        const int hsv_shift = 12;

        static int sdiv_table[256];
        static int hdiv_table180[256];
        static int hdiv_table256[256];
        static volatile bool initialized = false;

        int hr = hrange;
        //根据h的取值范围决定hdiv_table指向哪个数组
        const int* hdiv_table = hr == 180 ? hdiv_table180 : hdiv_table256;
        n *= 3;

        if( !initialized )
        {
            sdiv_table[0] = hdiv_table180[0] = hdiv_table256[0] = 0;
            for( i = 1; i < 256; i++ )
            {
                sdiv_table[i] = saturate_cast<int>((255 << hsv_shift)/(1.*i));
                hdiv_table180[i] = saturate_cast<int>((180 << hsv_shift)/(6.*i));
                hdiv_table256[i] = saturate_cast<int>((256 << hsv_shift)/(6.*i));
            }
            initialized = true;
        }

        for( i = 0; i < n; i += 3, src += scn )
        {
        	//提取分量
            int b = src[bidx], g = src[1], r = src[bidx^2];
            int h, s, v = b;
            int vmin = b;
            int vr, vg;

			/* 	
				注释中的代码位于precomp.hpp中
				
				 
				 extern const uchar icvSaturate8u_cv[]; //数组icvSaturate8u_cv[] 位于tables.cpp中
				 #define CV_FAST_CAST_8U(t)  ( (-256 <= (t) && (t) <= 512) ?icvSaturate8u_cv[(t)+256] : 0 )
				 #define CV_CALC_MIN_8U(a,b) (a) -= CV_FAST_CAST_8U((a) - (b))
				 #define CV_CALC_MAX_8U(a,b) (a) += CV_FAST_CAST_8U((b) - (a))

			*/
			/*获得v(vmax)和vmin*/
			//CV_CALC_MAX_8U(a,b) 利用宏命令和查表,将a,b中较大的数赋给a
			//CV_CALC_MIN_8U(a,b) 利用宏命令和查表,将a,b中较小的数赋给a
            CV_CALC_MAX_8U( v, g );
            CV_CALC_MAX_8U( v, r );
            CV_CALC_MIN_8U( vmin, g );
            CV_CALC_MIN_8U( vmin, r );
            
            /*计算s和h*/
            uchar diff = saturate_cast<uchar>(v - vmin);
            
            vr = v == r ? -1 : 0;
            vg = v == g ? -1 : 0;

            s = (diff * sdiv_table[v] + (1 << (hsv_shift-1))) >> hsv_shift;
            h = (vr & (g - b)) +
                (~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff))));
            h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift;
            h += h < 0 ? hr : 0;

            dst[i] = saturate_cast<uchar>(h);
            dst[i+1] = (uchar)s;
            dst[i+2] = (uchar)v;
        }
    }

    int srccn, blueIdx, hrange;
};

hsv转rgb uchar或ushort型的类HSV2RGB_b

struct HSV2RGB_b
{
    typedef uchar channel_type;

    HSV2RGB_b(int _dstcn, int _blueIdx, int _hrange)
    : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.0f / _hrange)
    {
    }

    void operator()(const uchar* src, uchar* dst, int n) const
    {
        int j = 0, dcn = dstcn;
        uchar alpha = ColorChannel<uchar>::max();

        for( ; j < n * 3; j += 3, dst += dcn )
        {
            float buf[6];
            buf[0] = src[j];
            buf[1] = src[j+1] * (1.0f / 255.0f);
            buf[2] = src[j+2] * (1.0f / 255.0f);
            //核心代码,调用了HSV2RGB_native
            HSV2RGB_native(buf, buf + 3, hscale, blueIdx);
            dst[0] = saturate_cast<uchar>(buf[3] * 255.0f);
            dst[1] = saturate_cast<uchar>(buf[4] * 255.0f);
            dst[2] = saturate_cast<uchar>(buf[5] * 255.0f);
            if( dcn == 4 )
                dst[3] = alpha;
        }
    }

    int dstcn;
    int blueIdx;
    float hscale;
};

inline void HSV2RGB_native(const float* src, float* dst, const float hscale, const int bidx)
{
    float h = src[0], s = src[1], v = src[2];
    float b, g, r;

    if( s == 0 )
        b = g = r = v;
    else
    {
        static const int sector_data[][3]=
            {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
        float tab[4];
        int sector;
        h *= hscale;
        if( h < 0 )
            do h += 6; while( h < 0 );
        else if( h >= 6 )
            do h -= 6; while( h >= 6 );
        sector = cvFloor(h);
        h -= sector;
        if( (unsigned)sector >= 6u )
        {
            sector = 0;
            h = 0.f;
        }

        tab[0] = v;
        tab[1] = v*(1.f - s);
        tab[2] = v*(1.f - s*h);
        tab[3] = v*(1.f - s*(1.f - h));

        b = tab[sector_data[sector][0]];
        g = tab[sector_data[sector][1]];
        r = tab[sector_data[sector][2]];
    }

    dst[bidx] = b;
    dst[1] = g;
    dst[bidx^2] = r;
}

通过对opencv代码的简单阅读,发现大量使用了查找表来简化计算:
https://blog.csdn.net/qq_23968185/article/details/51282049

2018-05-28 20:02:51 u014403318 阅读数 494

注释:本文翻译自OpenCV3.0.0 document->OpenCV-Python Tutorials,包括对原文档种错误代码的纠正

3.1 改变色彩空间

3.1.1 目标:

  • 这章节,学会如何转换图像的色彩空间,如BGR与Gray之间的转换,BGR与HSV之间的转换等
  • 创建一个在视频中提取彩色对象的程序
  • 学会这些函数:cv2.cvtColor()、cv2.inRange()等

3.1.2 改变颜色空间

在OpenCV中,有超过150种色彩空间转换的函数。但这里只介绍两种常用的:BGR与Gray,BGR与HSV。

函数cv2.cvtColor(input_image,flag),其中flag表示转换的类型从BGR到Gray用cv2.COLOR_BGR2GRAY。同样的BGR到HSV用cv2.BGR2HSV。

要获取所有的flag类型,在Python terminal种运行以下代码:

import cv2
flags = [i for i in dir(cv2) if startswith('COLOR_')]
print flags

Note:对于HSV,色相范围为[0,179],饱和度范围为[0,255],值范围为[0,255]。 不同的软件使用不同的刻度。 因此,如果您将OpenCV值与它们进行比较,则需要对这些范围进行规范化。

3.1.3 目标跟踪

在HSV中,表示颜色比RGB颜色空间更容易。在下面的应用程序中,我们尝试提取一个蓝色的对象,这里的方法是:

  1.  获取视频的每一帧
  2.   从BGR转换为HSV色彩空间
  3.   为HSV图像设置一系列蓝色阈值
  4.   单独提取蓝色对象

示例代码如下:

import cv2
import numpy as np

#传递参数0表示打开摄像头
cap = cv2.VideoCapture(0)

while (1):
    # 获取每一帧
    _, frame = cap.read()
    # 将BGR转换为HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # 定义HSV蓝色值的范围
    lower_blue = np.array([110, 50, 50])
    upper_blue = np.array([130, 255, 255])

    mask = cv2.inRange(hsv, lower_blue, upper_blue)

    res = cv2.bitwise_and(frame, frame, mask=mask)

    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)
    cv2.imshow('res', res)

    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

结果如下:


3.2 图像的几何变换

3.2.1 目标:

  • 学会图像的几种不同变换,如:旋转、平移、仿射变换等
  • 学习这些函数:cv2.getPerspectiveTransform()

3.2.2转换

OpenCV种提供了两种转换函数:cv2.warpAffine()和cv2.warpPerspective(),可以使用它们进行各种转换,cv2.warpAffine()需要一个2*3的矩阵,而cv2.warpPerspective()需要一个3*3的矩阵作为输入。

3.2.3 缩放

缩放只是调整图像的大小。因此,OpenCV带有一个函数cv2.resize()。可以手动指定图像的大小,也可以指定缩放因子。使用不同的插值方法,优先选择的插值方法是cv2.INTER_AREA用于缩小和cv2.INTER_CUBI(slow)&cv2.INTER_KINEAR用于缩放。

默认情况下,使用的插值方法是cv2.INTER_LINEAR用于所有调整大小的图像。

缩放的示例代码如下:结果是把图像放大了一倍

'''
图像缩放
'''
import cv2
import numpy as np

img=cv2.imread('1.jpg')
##cv2.INTER_CUBIC is slow
#res=cv2.resize(img,None,fx=0.25,fy=0.25,interpolation=cv2.INTER_CUBIC)


#OR
height,width=img.shape[:2]
res=cv2.resize(img,(width*2,height*2),interpolation=cv2.INTER_CUBIC)

cv2.imshow('res',res)
k=cv2.waitKey(0)
cv2.destroyAllWindows()

3.2.4 平移

平移是物体位置的移动。如果你知道移动方位(tx,ty),就可以创建变换矩阵并移动,变换矩阵M如下:


可以将其变换为np.float32类型的Numpy数组,并将其传递给cv2.warpAffine()函数。

平移变换的示例代码如下:

'''
图像的平移变换:关键是创建平移矩阵,如代码中的M
'''
import cv2
import numpy as np

img = cv2.imread('1.jpg', 0)
rows, cols = img.shape

M = np.float32([[1, 0, 100], [0, 1, 50]])   # 将矩阵变换为np.float32类型的Numpy数组,并将其传递给cv2.warpAffine函数
# cv2.warpAffine()函数的第三个参数是输出图像的size,opencv3种必须以元组(width,height)的格式,
# 原文档中是分别传递width,height其实是错误的
# width=the number of columns,height=the number of rows
dst = cv2.warpAffine(img, M, (cols, rows))  # 第三个参数是输出图像的大小应该是(width,height)的格式

cv2.imshow('img', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:


3.2.5 旋转

通过图像的变换矩阵来实现角度的旋转,变换矩阵如下:


但是OpenCV提供了可调节的旋转中心的旋转缩放,以便您可以在任何您喜欢的位置进行旋转。旋转矩阵变为:

其中:


要找到这个旋转矩阵,OpenCV中提供了一个cv2.getRotationMatrix2D()。

旋转的示例代码如下:

'''
图像旋转:得到旋转矩阵,使用cv2.getRotationMatrix2D()函数
将图像相对于中心旋转了90度,没有任何缩放
'''
import cv2

img = cv2.imread('1.jpg', 0)
rows, cols = img.shape

M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 90, 1)
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('res', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2.6 仿射变换

在仿射变换中,原始图像中所有平行线在输出图像中仍然是平行的。为了找到转换矩阵,我们需要输入图像中的三个点和它们在输出图像中的对应位置。然后,cv2.getAffineTransform()将创建一个2*3的矩阵,并传递给cv2.warpAffine().

仿射变换的示例代码如下:

'''
仿射变换:
1.在仿射变换中,原始图像中所有平行线在输出图像中仍然是平行的
2.也需要一个转换矩阵:需要输入图像中的三个点和它们在输出图像中的对应位置
3.用cv2.getAffineTransform()创建一个2*3的矩阵,传递给cv2.warpAffine()
'''
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('1.jpg')
rows, cols, ch = img.shape

# 输入点位置和输出点位置
pst1 = np.float32([[50, 50], [200, 50], [50, 200]])
pst2 = np.float32([[10, 100], [200, 50], [100, 50]])

# 通过输入点位置和输出点位置得到的变换矩阵
M = cv2.getAffineTransform(pst1, pst2)

dst = cv2.warpAffine(img, M, (cols, rows))
plt.subplot(121), plt.imshow(img), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()

结果:


3.2.7 透视变换

对于透视变换,需要一个3*3的变换矩阵。即使变换后,直线仍然保持直线,要找到此变换矩阵,需要输入图像上的四个点和输出图像上的对应点。在这4个点中,3个不应该共线。转换矩阵可以通过cv2.getPerspectiveTransform()找到,然后将这个3*3的矩阵应用到cv2.warpPerspective().

透视变换的示例代码如下:

'''
透视变换:
1.需要一个3*3的矩阵
2.变换后,直线仍然是直线
3.找到变换矩阵,需要输入图像上的四个点和对应的输出点(四个点中三个不应该共线)
4.变换矩阵可以通过cv2.getPerspectiveTransform()找到
5.最后将变换矩阵应用到cv2.warpPerspective()
'''
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('1.jpg')
rows, cols, ch = img.shape

# 四个输入点坐标及对其在输出图像中的对应左边
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])

# 获得变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)

# 将变换矩阵应用到cv2.warpPerspective()
dst = cv2.warpPerspective(img, M, (300, 300))

plt.subplot(121), plt.imshow(img), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()

结果:




2019-09-15 16:31:09 happyhorizion 阅读数 77

基本概念

RGB空间

RGB 是最基本、最常用、最接近硬件的色彩空间表示。

在这里插入图片描述

但是真实世界中还有光照、遮挡、阴影等多种情况,而且人眼对RGB三种颜色分量的敏感度也是不一样的,如果色彩的相似性直接用欧式距离来度量,结果会与视觉直观有很大差距。
所以,RGB适合与显示系统,但是不适合图像处理。

openCV提取不同通道的颜色

import cv2 as cv
src=cv.imread('rgb.jpg')
cv.namedWindow('first_image', cv.WINDOW_AUTOSIZE)
cv.imshow('first_image', src)

#三通道分离形成单通道图片
b, g, r =cv.split(src)
cv.imshow("second_blue", b)
cv.imshow("second_green", g)
cv.imshow("second_red", r)

在这里插入图片描述

HSV空间

  • H:Hue,色调,色相
  • S:Saturation,饱和度,色彩纯净度
  • V:value,明度

HSV更接近人眼的直观感受。具体来说:

H参数表示色彩信息,即所处的光谱颜色的位置。该参数用角度量来表示,红、绿、蓝分别相隔120度。互补色分别相差180度。

纯度S为一比例值,范围从0到1,它表示成所选颜色的纯度和该颜色最大的纯度之间的比率。S=0时,只有灰度。

V表示色彩的明亮程度,范围从0到1。有一点要注意:它和光强度之间并没有直接的联系。

怎么理解HSV呢?

这里引入极坐标系,红蓝绿三个颜色分别位于0度,120度和240度,在色彩极坐标系中,“纯度”与当前色彩的角度位置有关,越接近红-绿-蓝对应的角度,因此,纯度也称为色相,顾名思义,就是用当前色彩与三原色之间的相位关系来描述。

在极坐标系中,矢量除了相位以外,还有“模”的关系,原点是“灰色”,模值越大,色彩就越鲜艳,最大值是255。这里的“模”值就是饱和度。
在这里插入图片描述
但是如何形容颜色的亮度呢?我们引入三维直角坐标系,三个坐标轴分别表示RGB的取值。很显然,原点(0,0,0)是黑色,(255,255,255 )是白色,(255,0,0)红色,(0,255,0)绿色,(0,0,255)蓝色。
如果从原点出发,到(255,255,255)白色连一条对角线,这条对角线就是“明度”轴了。越接近原点就越“暗”, 越接近白色的对角点就越“亮”。

在这里插入图片描述
如果回到之前的极坐标系,亮度应该如何表示呢?显然,我们需要引入一个纵轴表示明暗关系。
在这里插入图片描述
但是上面的图并不是特别“科学”,因为最“暗”的原点处,应该是一个点,整个色彩空间应该是一个圆锥的形状。
在这里插入图片描述

  • openCV 中HSV色彩空间的转换

跑一下openCV 帮助文档中的经典例子,随手拿起手边的蓝色电脑内胆包被成功捕获了。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Sep 15 15:05:19 2019
"""

import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
    # Take each frame
    _, frame = cap.read()
    # Convert BGR to HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # define range of blue color in HSV
    lower_blue = np.array([100,50,50])
    upper_blue = np.array([140,255,255])
    # Threshold the HSV image to get only blue colors
    mask = cv2.inRange(hsv, lower_blue, upper_blue)
    # Bitwise-AND mask and original image
    res = cv2.bitwise_and(frame,frame, mask= mask)
    cv2.imshow('frame',frame)
    cv2.imshow('mask',mask)
    cv2.imshow('res',res)
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

在这里插入图片描述
注意其中这一句:

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

这一句是将摄像头捕获的色彩从RGB空间转换到HSV空间,随后的代码用HSV方式指定特定的色彩范围。第一个值是H,就是色相,在openCV的HSV定义中,蓝色是在120度,这里指定100-140之间,S和V的取值在50-255之间。
更多色彩转换,见帮助文档: https://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html

HSL空间

HSL与HSV的定义很类似,H也是色相,S也是饱和度,L则代表brightness,是亮度。亮度越高,越接近白色,越低,越接近黑色。而HSV中的最后一个值明度,越小越接近黑色,越大,色彩越鲜明。可见,HSL的定义更符合人眼的视觉感受。
H:
在这里插入图片描述
S:
在这里插入图片描述
L:
在这里插入图片描述

色彩变换

灰度变换

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

im0 = Image.open('car.jpg')

im_grey = im0.convert('L') # 灰度变换
im_grey.show()

在这里插入图片描述

色彩反向、调整像素区间

im = np.array(im_grey)
im2 = 255-im # 对图像进行反向处理
im3 = (100/255)*im+100 #将图像的像素变换到100-200之间
im4 = 255*(im/255)**2 # 对图像像素值平方后得到的图像

plt.subplots()
plt.subplot(131), plt.imshow(im2)
plt.subplot(132), plt.imshow(im3)
plt.subplot(133), plt.imshow(im4)

在这里插入图片描述

增强对比度

对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比度越大,差异范围越小代表对比度越小。

对比度增强技术主要解决图像灰度级范围较小造成的对比度低问题,目的是将图像的灰度级放大到指定的程度,使图像中的细节看起来更加清晰。

在这里插入图片描述

直方图均衡化

直方图均衡化是将一副图像的灰度直方图变平,使得变换后图像中的每个灰度值的分布概率相同。该方法通常用于是灰度值进行归一化,可以增强图像的对比度。

# 直方图均衡化
import numpy as np

def histeq(im, nbr_bins=256):
    # 计算图像的直方图
    imhist, bins = np.histogram(im.flatten(), nbr_bins, normed=True)
    cdf = imhist.cumsum() # 累计分布函数
    cdf = 255*cdf/cdf[-1] # 归一化
    im2 = np.interp(im.flatten(), bins[:-1], cdf)
    
    return im2.reshape(im.shape), cdf


from PIL import Image
import matplotlib.pyplot as plt

im0 = Image.open('car.jpg')

im_grey = np.array(im0.convert('L')) # 灰度变换, 并转化为numpy array

im2,cdf = histeq(im_grey)

plt.subplots()
plt.subplot(121), plt.imshow(im_grey)
plt.subplot(122), plt.imshow(im2)

在这里插入图片描述

图像平滑/减少噪声

图像平均

图像平均是一种减少图像噪声的简单方式,通常用于艺术特效。简单滴说就是将所有图像求和做平均。

高斯滤波

将图像与高斯核做卷积得到
Iσ=IGσ I_\sigma = I * G_\sigma
其中I代表一个图像,G表示标准差为δ\delta 的二维高斯核
Gσ=12πσ2e(x2+y2)/2σ2G_\sigma = \frac{1}{2\pi\sigma^2}e^{-(x^2+y^2)/2\sigma^2}

from PIL import Image
from numpy import *
from scipy.ndimage import filters

# 对灰度图模糊
im = array(Image.open('car.jpg').convert('L'))
im2 = filters.gaussian_filters(im,5)

# 对彩色图模糊, 要求每个通道进行操作
im = array(Image.open('car.jpg'))
im2 = zeros(im.shape)
for i in range(3):
	im2[:,:,i] = filters.gaussian_filter(im[:,:,i],5)
im2 = unit8(im2)

openCV也提供了很多滤波工具,例如:

blur: 对各种噪声都有一定的抑制作用
GaussianBlur: 对随机噪声比较好,对椒盐噪声效果不好
medianBlur: 对椒盐噪声效果比较好
fastNlMeansDenoising: 非局部去噪,速度很慢,可以调参的去噪方法, 只支持输入是灰度图像的
fastNlMeansDenoisingColored: 同上,去噪针对彩色图像

椒盐噪声就是非常零散的,近似呈均匀分布的散点状白色/黑色噪声,如下图。对椒盐噪声中值滤波效果比较好,对高斯噪声非局部均值去噪效果比较好.
在这里插入图片描述

图像梯度

图像的梯度向量包括两层含义,一个是梯度的大小, 描述了图像强度变化的大小,另一个是梯度的方向,描述了图像强度变化的方向。

sobel算子/scharr算子

Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好,可以设定求导的方向(xorder 或 yorder),还可以设定使用的卷积核的大小(ksize),如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。 3x3 的 Scharr 滤波器卷积核如下

在这里插入图片描述

prewitt算子

Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。
在这里插入图片描述

Laplacian 算子

拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶 Sobel 导数,事实上, OpenCV 在计算拉普拉斯算子时直接调用 Sobel 算子。
  在这里插入图片描述

scipy和opencv都提供了相应工具,例如:

from PIL import Image
from numpy import *
from scipy.ndimage import filters

im = array(Image.open('car.jpg').convert('L'))

# sobel filter
imx = zeros(im.shape)
filters.sobel(im,1,imx)

imy = zeros(im.shape)
filters.sobel(im, 0, imy)

matnitude = sqrt(imx**2+imy**2)

import matplotlib.pyplot as plt

plt.subplots()
plt.subplot(121), plt.imshow(imx)
plt.subplot(122), plt.imshow(imy)

在这里插入图片描述
prewitt滤波器, 也可以调用scipy.ndimage的filters模块得到。

opencv中,直接调用Sobel函数或者Laplacian函数就可以, 例如:


import cv2
from matplotlib import pyplot as plt 

img = cv2.imread('me.jpg',0)

laplacian = cv2.Laplacian(img, cv2.CV_64F)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0,ksize=5)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1,ksize=5)


plt.subplot(2,2,1),plt.imshow(img,cmap='gray')
plt.title('Original'),plt.xticks([]),plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap='gray')
plt.title('Laplacian'),plt.xticks([]),plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap='gray')
plt.title('Sobel_X'),plt.xticks([]),plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap='gray')
plt.title('Sobel_Y'),plt.xticks([]),plt.yticks([])
plt.show()


在这里插入图片描述

参考及更多阅读

OpenCV图像噪声与去噪函数方法对比使用介绍:
https://cloud.tencent.com/developer/article/1165771
opencv图像梯度:
https://blog.csdn.net/u010682375/article/details/70140803
opencv 彩色图像对比度增强:

HSV色彩空间的理解

阅读数 2580

数字图像处理

阅读数 809

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