图像的分割一般是用来把具有相同特性的连续区域依次分割开来,这在视觉处理技术中也是很常用的归类算法之一。
运动物体检测一般在动态图像中较为常用,如果在某一帧锁定了特征物块,那么可以在连续的图像中跟踪特征物块的具体位置,然后输出坐标或者其他量供使用,其在机器视觉上的运用最为广泛,因为其具有锁定目标的功能,有了这个功能机器才具有真正的智能性、灵敏性。
4.4.6.1 颜色
通过图像的颜色信息来了解图像的特征是一个非常有用的思路,不同的颜色代表着不一样的信息,下面来欣赏一下梵高的作品《星空》,如图4.4.20所示。
图4.4.20 梵高的作品《星空》
在SimpleCV视觉处理框架中,单个像素的颜色可以通过getPixel()函数来获取:
from Simple CV import Image
img = Image('starry_night.png')
print img.get Pixel(0, 0)①
① 在显示屏上打印获取图像像素坐标(0,0)的RGB三基色值,在这里也就等于(71.0, 65.0,54.0)。
在颜色表示方式中RGB有一个很大的缺点,它并不能直观地表示亮度值的模型。然而,在视觉处理中亮度是最常见的控制属性,在理论上,亮度与R、G、B之间有一定的关系,然而在实践中,需要很直观地通过亮度来区分不同的特征。
例如,淡黄色和深黄色之间的差异是由蓝色值这个非直观的因素控制的。那么在实践操作中,不能直观地去控制蓝色的比例,解决这个问题的方法是采用HSV颜色坐标系表示,它由色调(H)、饱和度(S)、亮度值(V)一起定义整个图像。这样亮度就有一个值和它相对应。它们之间仅仅通过一个转换就可以完成,因为在RGB空间中的所有颜色都在HSV空间中有对应的独特色彩,反之亦然。这样就很容易完成RGB和HSV颜色空间之间的转换,程序如下:
from Simple CV import Image
img = Image('starry_night.png')
hsv = img.to HSV() ①
print hsv.get Pixel(25,25) ②
rgb = hsv.to RGB() ③
print rgb.get Pixel(25,25)④
① 把图像从RGB颜色空间转换到HSV颜色空间。
② 这一行为打印语句,由于图像被转换到HSV颜色空间,所以将打印像素为(25,25)的HSV值。在这种情况下,这个值为(117.0,178.0,70.0)。
③ 把这个图像转换回RGB颜色空间。
④ 这时候打印出来的则是RGB颜色空间下的值,这里为(21.0,26.0,70.0)。
当操作一个图像对象时,有很多高光和反光处理部分,利用HSV颜色空间处理起来就比较简单。在HSV颜色空间中,镜面反射将具有高亮度值(V)和一个较低的饱和度值(S)的组成部分。而色相(H)成分对于纯色的对象来说,在不同光照下具有相同的值。这对于我们进行图片的分割是很有好处的。
在SimpleCV框架开发中把图形转换为灰度图是最常用的亮度分析方法,一个灰度图形中只有亮度信息,缺少任何颜色分量,它经常被称为黑白图片,但是要理解它与二值化图片有着本质上的区别,二值化处理图片后得到的是黑色和白色两种纯色。相反,灰度图片如果表示一个8位的颜色,那么相当于每一个颜色通道是0~255级分辨率的,分别表示红色、绿色和蓝色。若要建立一个灰度图像则需要获取R、G、B,并将之转换为单色,则对三者加权求平均值:
from Simple CV import Image
img = Image('starry_night.png')
gray = img.grayscale() ①
print gray.get Pixel(0,0)②
① 将图像转换为灰度图像,结果如图4.4.21所示。
② 在屏幕上打印像素(0,0)的灰度值,结果为(66.0,66.0,66.0)。
图4.4.21 灰度图片
请注意,运行程序将返回三个相同数据。在RGB和HSV颜色空间中这将保持一致的格式,都返回三个值。然而,由于灰度级只有一个值,表示亮度,故相同的值被重复三次,以获得针对特定像素的灰度值,而不必将图像转换为灰度图像。
4.4.6.2 颜色分割
上面简单地介绍了分割的概念,它是将图像划分为多个具有相同特性的需要的过程,在这个过程中,相同特征可以转换为一个类,具有相同特征,对其常用颜色来划分。在常见的环境中,特征物体都有一个比较鲜艳的颜色来区分背景色,如跟踪一个红色气球等,在这种情况下,使用颜色差来分割图像,并去除图像的背景,只留下感兴趣的对象。
分割图像这个过程主要是通过对一个图像做颜色减法来实现的。若要理解这一点,首先考虑如何对每个像素做颜色减法。假设像素点(0,0)是紫色,RGB三基色的值为(100,0, 100)。可以采取相同的三基色值(100,0,100),然后用原始三基色减去样本三基色。仔细理解,为什么要这么做。对每个像素做这样的减法操作,如(100,0,100)-(100,0,100)=(0, 0,0)。由于(0,0,0)是黑色的RGB值,这样会得到一个黑色像素点,也就是说具有相同颜色的像素点会转换为黑色,而不同颜色的像素也可以彼此相减。例如,(100,0,100)-(90, 0,10)=(10,0,90),这样得到的就不是一个黑色像素点。
可以利用colorDistance()函数对每个像素进行运算,这个函数中有一个参数,也就是目标颜色。想进一步理解这个过程,可以通过一个例子进行介绍。图4.4.22所示为一个黄色胶枪图片。通过颜色分割处理后的图片如图4.4.23所示。
from Simple CV import Image, Color
yellow Tool = Image("yellowtool.png")
yellow Dist = yellow Tool.color Distance((223, 191, 29))
yellow Dist Bin = yellow Dist.binarize(50).invert()
yellow Dist Bin.show()
可以观察上面的图片显示为黑色,也可以把这个提取出来的图像还原为黄色,如图4.4.24所示。
图4.4.22 黄色胶枪图片
图4.4.23 通过颜色分割处理后的图片
from Simple CV import Image, Color
yellow Tool = Image("yellowtool.png")
yellow Dist = yellow Tool.color Distance((223, 191, 29))
yellow Dist Bin = yellow Dist.binarize(50).invert()
only Yellow = yellow Tool - yellow Dist Bin
only Yellow.show()
图4.4.24 还原特征颜色值
4.4.6.3 举例
例程:圆形(球)追踪。
这个例子演示了如何在屏幕上跟踪一个圆形的物体(见图4.4.25),在例子中最重要的一点是,它保持跟踪前模板信息,然后根据当前模板在视频的下一帧中寻找相同的对象。
from Simple CV import Camera, Color, Display
cam = Camera()
disp = Display()
previous_ball_xy = None
previous_ball_size = 100
while disp.is Not Done():
img = cam.get Image()
dist = img.color Distance(Color.BLACK).dilate(2)
segmented = dist.binarize()
blobs = segmented.find Blobs(minsize=2000)
if blobs:
circles = blobs.filter([b.is Circle(0.2) for b in blobs])
if circles:
if previous_ball_xy:
fcircles = circles.filter([c.radius() 〉
(previous_ball_size * 0.5) for c in circles])
distances = [int(c.distance From(previous_ball_xy))
for c in fcircles]
nearest = blobs[distances.index(min(distances))]
img.draw Circle((nearest.x, nearest.y), nearest.radius(),
Color.RED, thickness=4)
previous_ball_xy = (nearest.x, nearest.y)
previous_ball_size = nearest.radius()
else:
previous_ball_xy = (circles[-1].x, circles[-1].y)
previous_ball_size = circles[-1].radius()
else:
img.draw Text("No circles found")
img.save(disp)
图4.4.25 跟踪圆形物体
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。