赞
踩
《我的眼睛–图灵识别》第三章:基础:颜色识别
七色彩虹
漂亮的彩虹是一种光学现象,使用三棱透镜进行折射就能看到七色彩虹。它分别由红、橙、黄、绿、青、蓝、紫7种颜色组成。色彩按字面含义上理解可分为色和彩,色是指人对进入眼睛的光并传至大脑时所产生的感觉;彩则指多色的意思,是人对光变化的理解。
1、颜色描述
颜色是通过光射向物体产生了反射光,不同光的波长和强度对肉眼产生刺激,引起视觉神经和中枢神经反应,大脑接收到相应的信号后,通过日常文化认识作出语义上的定义。
自然界的色彩是十分复杂的,我们处在一个五彩斑斓的世界中,日常口语化中描述的颜色不足以准确表达出我们想要的颜色,例如红色?要再亮一点?再深一点?这种模棱两可的描述在编程中将会是一种灾难问题,所以我们需要通过准确的术语来表示具体的一种颜色。
原色的一个概念性词汇,指由不同的颜色(原色)组合形成更多颜色。在不同的场景中,原色的构成并不一样。
光学三原色
在光学中,一般认为红色、绿色和蓝色是一组原色,又称为光学三原色,是一种叠加型原色。这是由于人类拥有的三种视锥细胞对红光、绿光和蓝光最为敏感。通过不同比例的红绿蓝颜色叠加,可以使人看到各种颜色。例如红色与绿色混合产生黄色或橙色,绿色和蓝色混合产生青色,蓝色和红色混合产生紫色或品红色。当这三种颜色等比例叠加到一起时会变成灰色,如果将三种颜色饱和度均调至最大时则呈现白色。电视机、摄像机、计算机和手机显示屏等都是运用了光学三原色原理。
(RGB)红绿蓝三原色
颜料三原色
在印刷、绘画等情况下,一般认为青色、洋红色和黄色是一组原色,又称为美术三原色,是一种消减型原色。例如黄色和青色混合产生绿色,黄色和洋红色混合产生红色,洋红色和青色混合产生蓝色。当这三种等比例混合时呈现灰色,如果将饱和度调至最大,理论上会呈现黑色,但是实际上由于颜料的原因会呈现出浊褐色。因此,在印刷技术上加入了第四种原色——黑色,以弥补颜料三原色的不足。
(CMYK)红黄蓝三原色
其他原色
除了以上两种常见的三原色外,还有一些其他的原色组,例如心理原色中采用蓝色、黄色、红色、绿色、橙色和紫色这六种心理原色加上黑白两色,形成了色彩感知。再例如天然彩色相片技术中采用橙色、绿色、紫色为三原色等。
2、色彩空间
随着技术的发展,各种各样的色彩空间被创造出来,有RGB、HSV(HSB)、HSL、CMYK等等。本书中只用到RGB和HSV色彩空间格式的颜色值。
RGB
光学三原色系统一般称为”RGB色彩空间“,也就是由红(Red:0255)、绿(Green:0255)、蓝(Blue:0~255)所组合呈现的色彩系统。它的几何空间模型是一个正方体,由3个向量构成,空间中每一个点都表示一个颜色。在这个空间中,可以通过以下几种不同的数值来准确描述一个点的颜色。
RGB色彩空间模型
RGB色彩总共能组合出约1678万种色彩,即三个分量最大值进行相乘256×256×256=16777216。通常被简称为1600万色或千万色,也称为24位色(2的24次方)。
虽然RGB色彩空间适合用在各种显示屏上,但是它的色彩描述并不适合人类理解,因为我们的眼睛无法识别出一个颜色中红蓝绿三者的比重大小。例如RGB色彩描述为“BB5280”表示什么颜色?一般只有通过查询才能知道这个颜色长啥样。
颜色互补色
色彩中的互补色有红色与青色互补、蓝色与黄色互补、绿色与品红色互补等等。在光学三原色中指两种颜色以适当的比例混合而能产生白色时,则这两种颜色就称为“互为补色”,比如:RGB(255,0,0)和RGB(0,255,255),就是说它们的每个分量值分别加起来后能够等于255。
互补色
HSV(HSB)
由于RGB色彩空间描述不适合人类理解,我们看颜色一般是通过对颜色的色相、饱和度、明度来识别的,故在此基础上引申出了另一种新的模型结构——HSV色彩空间,这种模型是采取圆柱坐标系的方法进行构建。HSV即色相(Hue)、饱和度(Saturation)、明度(Value),又称为HSB,其中B的英文是Brightness。
HSV色彩空间模型
色相(H)是色彩的颜色描述,例如平时说的红色、蓝色等,取值0~360。
饱和度(S)是指色彩的纯度,饱和度越高,颜色越鲜艳,饱和度变低时,颜色逐渐变暗淡,取值范围是0~100%。
明度(V)是指颜色的亮度,越高越亮,越低越暗,取值范围是0~100%。
颜色转换
什么时候需要进行颜色转换?
一般情况下,通过RGB色彩空间来查找颜色是够用的,但是当遇到一些颜色随时间或天气变化而产生一些不同,例如乌云变浓变淡、白天变亮、夜晚变暗等,RGB色彩空间就显得很局限了,这时候就需要引入HSV色彩空间来解决这个问题。
HSV色彩空间可以通过肉眼直观的描述来定义某一个颜色。比如一块红色的纸张,正常情况下看到的是标准的红色;当白天被阳光照射后,看到的是粉红色;到了夜晚光线变暗,看到的是枣红色。
变化的红色
VB6代码:
调用例子:
- Dim iHSV As HSV, iRGB As RGB
- iHSV =RGB转HSV(255, 0, 0)
- MsgBox iHSV.Hue& "," &iHSV.Saturation & "," &iHSV.Value
-
- iRGB =HSV转RGB(0, 100, 100)
- MsgBox iRGB.Red& "," &iRGB.Green& "," & iRGB.Blue
封装函数:
- Public Type HSV
- Hue As Integer
- Saturation As Integer
- Value As Integer
- End Type
- Public Type RGB
- Red As Integer
- Green As Integer
- Blue As Integer
- End Type
-
- Private Function Max(c1 As Single, c2 As Single) As Single
- If c1 > c2 Then
- Max = c1
- Else
- Max = c2
- End If
- End Function
- Private Function Min(c1 As Single, c2 As Single) As Single
- If c1 > c2 Then
- Min = c2
- Else
- Min = c1
- End If
- End Function
-
-
- '转换RGB到HSV
- Public Function RGB转HSV(ByVal R As Integer, ByVal G As Integer, ByVal b As Integer) As HSV
- Dim nH As Single, nS As Single, nV As Single
- Dim nR As Single, nG As Single, nB As Single
- Dim ndelR As Single, ndelG As Single, ndelB As Single
- Dim nmax As Single, nmin As Single, ndelMax As Single
- nR = R / 255
- nG = G / 255
- nB = b / 255
- nmax = Max(Max(nR, nG), nB)
- nmin = Min(Min(nR, nG), nB)
- ndelMax = nmax - nmin
- nV = nmax
- If (ndelMax = 0) Then
- nH = 0
- nS = 0
- Else
- nS = ndelMax / nmax
- ndelR = (((nmax - nR) / 6) + (ndelMax / 2)) / ndelMax
- ndelG = (((nmax - nG) / 6) + (ndelMax / 2)) / ndelMax
- ndelB = (((nmax - nB) / 6) + (ndelMax / 2)) / ndelMax
- If (nR = nmax) Then
- nH = ndelB - ndelG
- ElseIf (nG = nmax) Then
- nH = (1 / 3) + ndelR - ndelB
- ElseIf (nB = nmax) Then
- nH = (2 / 3) + ndelG - ndelR
- End If
- If (nH < 0) Then nH = nH + 1
- If (nH > 1) Then nH = nH - 1
- End If
- RGB转HSV.Hue = nH * 360
- RGB转HSV.Saturation = nS * 100
- RGB转HSV.Value = nV * 100
- End Function
-
-
按键精灵2014脚本:
调用例子:
- //色相(H)、饱和度(S)、明度(V)
- //下面这句是把16进制颜色("0000FF")转换分解到10进制(H, S, V)分量中
- Call Plugin.TULING.RGBtoHSV("0000FF",H,S,V)
- MessageBox H & "," & S & "," &V
-
- hColor=Plugin.TULING.HSVtoRGB(0,100,100)
- MessageBox hColor
3、获取颜色
屏幕坐标系
在生活中,我们要去某一个地方,需要知道详细的地址,例如人民路168号1栋608房间。而在我们屏幕中,如果要知道某一个点的具体位置时,就可以利用坐标这个概念来描述。
屏幕坐标就是表示一个点在固定分辨率屏幕上的位置数值。当一个屏幕的分辨率是1920*1080大小时,屏幕坐标最左上角的点坐标就是(0,0),屏幕最右下角的坐标就是(1919,1079),因为0到1919一共有1920个数字,正好对应1920个点,垂直方向也一样。屏幕上任意一个点都有唯一的坐标,所以我们就通过坐标来表达某个点所在的位置。
屏幕坐标系是以屏幕最左上角为起点的坐标系,从左往右为X轴方向(范围在01919),从上往下为Y轴方向(范围在01079),凡超出这个范围值的为越界,用户在屏幕上就无法看到。这就跟我们数学中的十字坐标系非常相似,两者唯一区别是y轴的方向是相反的。
屏幕坐标系
获取指定坐标点颜色
屏幕上显示着各种各样的颜色,这对我们写条件时经常要用到的颜色判断,要想知道屏幕上的某个位置颜色是否发生变化,就需要对指定位置的颜色进行获取,之后才能对获取的颜色值进行相应的判断操作。
直接通过“鱼鱼抓点抓色“工具(或者其他第三方工具)进行获取当前鼠标下坐标点的颜色或者输入指定屏幕坐标来获取颜色。当然也可以调用微软API的GetPixel函数对指定屏幕坐标进行颜色的获取。
鼠标位置颜色
指定坐标颜色
你们有没有这样的怀疑过,取色判断跟图像识别应该没有任何关系的吧?
其实,在日常生活中大家都是有体验过的,对吧?没有吗?
红绿灯
日常生活中最容易见到的就是“红绿灯”啦,开车的看到红灯就会停车,对吧?
你看到的这些根据人眼判断的就是一种识别,只是你没有意识到而已,对不对?这个就是根据一种颜色来判断,一种最简单的识别方法。
那么我们可以说,颜色判断就是一种最最基础的图像识别方法。
但是,有的时候,我们无法单纯的只靠一种颜色来识别,因为这样会很容易出现识别错误,比如:看到红色的广告牌就认为是红灯吗?此时就需要大范围内的多种颜色一起进行判断,就是我们经常说的多点找色(多点找色也是找图的一种形态,详情查阅:04基础:图片识别)。
VB6代码:
调用例子:
- Dim 颜色 As String
- 颜色 = 来源_获取屏幕位置颜色(100, 200)
- MsgBox 颜色
封装函数:
- Public Function 来源_获取屏幕位置颜色(x As Long, y As Long) As String
- Dim WindowDC As Long, 颜色 As String
- On Error GoTo ErrLine
- WindowDC = GetDC(0) '获取全屏幕场景
- 颜色 = GetPixel(WindowDC, x, y) '取场景中(x, y)坐标的颜色
- ReleaseDC 0, WindowDC '释放场景
- 来源_获取屏幕位置颜色 = Right("000000" & UCase(Hex(颜色)), 6)
- Exit Function
- ErrLine:
- 来源_获取屏幕位置颜色 = ""
- End Function
按键精灵2014脚本:
调用例子:
- 颜色 = Plugin.TULING.GetPixelColor(100, 200)
- TracePrint 颜色
获取屏幕像素
仅仅通过一个个指定坐标点来获取屏幕上的所有颜色,遍历效率那是超级的慢,简直是在浪费生命,我们希望的是能够一次性的快速获取屏幕上的所有颜色。使用微软API提供的BitBlt和GetDIBits函数,就能够很轻松的一次性获取屏幕指定区域范围内的所有像素点的颜色数据。
VB6代码:
调用例子:
- Dim 图像数据() As Byte
- Call 来源_获取屏幕像素(0, 0, 200, 100, 图像数据)
封装函数:
- Public Sub 来源_获取屏幕像素(左 As Long, 上 As Long, 右 As Long, 下 As Long, 返回图像数据() As Byte)
- Dim Temp图像数据() As Byte, bi24BitInfo As BitMapInfo
- Dim 宽 As Long, 高 As Long
- 宽 = 右 - 左 + 1 '图像宽度
- 高 = 下 - 上 + 1 '图像高度
- ReDim Temp图像数据(3, 宽 - 1, 高 - 1) As Byte
- With bi24BitInfo.bmiHeader
- .biBitCount = Bits
- .biCompression = 0&
- .biPlanes = 1
- .biSize = Len(bi24BitInfo.bmiHeader)
- .biWidth = 宽
- .biHeight = -高 '显示正常图像
- End With
- ……略…
- 返回图像数据 = Temp图像数据
- End Sub
按键精灵2014脚本:
调用例子:
- Call Plugin.TULING.Pixel_FromScreen(0,0,200,100)
- //显示获取的图像
- Call Plugin.TULING.Pixel_Preview()
4、颜色的查找识别
考虑到不同的电脑分辨率大小就会有所不同,需要找的目标(颜色)出现的位置可能会不一样,我们并不知道它在屏幕上是在具体的哪个位置,如果要想找到它,可以通过对屏幕上的颜色数据进行一一遍历和判断,这样就能知道所要找的目标颜色在屏幕上的位置是哪个坐标值,进而找到它。
下面举个例子,如何利用颜色找到电脑桌面上的“计算机”图标?
(Win7)计算机
首先,打开鱼鱼抓色工具,勾选或按热键【Alt+~】启动取色功能,把鼠标移动到“我的电脑”图标的淡绿色点上(其实选择其它任意颜色点也是可以的)。
启动取色功能
然后,按下热键【Alt+~】停止取色。这样,就完成了“计算机”图标的颜色获取。
抓取到颜色值
接下来,就能够在屏幕区域(左边:0, 上边:0, 右边:1919, 下边:1079)范围内使用16进制的颜色值“00FF6B”进行查找,最终返回找到的颜色在屏幕上的具体坐标值。
需要特别注意的是,要查找的颜色必须在指定的区域范围内。
在屏幕上的具体坐标值
颜色查找方向
在指定区域范围内查找颜色时,一般默认的情况下是从左上到右下的方式进行遍历,如果你要找的颜色刚好在右下角时,还用这种方向进行遍历就会浪费很多时间,这个时候你就可以对查找方向的参数进行设置,使其为从右下到左上的方式进行遍历。以下提供了8种遍历方式。
颜色查找方向
问题:
如何进行多个颜色(红、黄、蓝)查找识别,并返回每个颜色的坐标?
(作业)多个颜色查找
VB6代码:
调用例子:
- Dim FoundX As Long, FoundY As Long, 颜色 As String
- 颜色 = "0000FF"
- Call 查找_屏幕区域找单色(0, 0, 1024, 768, 颜色, 0, 1, FoundX, FoundY)
- Debug.Print FoundX, FoundY '输出找到的坐标
封装函数:
- 'Call 查找_屏幕区域找单色(
- ' 区域左边:长整数,
- ' 区域上边:长整数,
- ' 区域右边:长整数,
- ' 区域下边:长整数,
- ' 查找颜色:字符串,
- ' 查找方向:整数[0-从左上往右下;1-从左下往右上;2-从右上往左下;3-从右下往左上,4-从上左往下右;5-从上右往下左;6-从下左往上右;7-从下右往上左],
- ' 颜色相似度:单精度[0.5到1之间;1为精确匹配],
- ' 输出找到的x坐标:整型变量,
- ' 输出找到的y坐标:整型变量
- ' )
- Public Sub 查找_屏幕区域找单色(左 As Long, 上 As Long, 右 As Long, 下 As Long, 颜色值 As String, 查找方向 As Integer, 相似度 As Single, FoundX As Long, FoundY As Long)
- Dim 结果x As Long, 结果y As Long
- 结果x = -1
- 结果y = -1
- 'On Error GoTo 结束
- '1.截取屏幕图片信息
- Dim 屏幕像素数据() As Byte
- Call 来源_获取屏幕像素(左, 上, 右, 下, 屏幕像素数据)
- '2.相似度计算
- Dim 颜色相似度 As Long, flag As Boolean
- 颜色相似度 = (1 - 相似度) * 255
- '3.拆解颜色值分量
- Dim 颜色 As Long, Red As Byte, Green As Byte, Blue As Byte
- 颜色 = CLng("&H" & 颜色值)
- Red = 颜色 Mod 256: Green = (颜色 256) Mod 256: Blue = 颜色 256 256
- '4.颜色的查找识别
- Dim x As Long, y As Long, 宽 As Long, 高 As Long
- 宽 = 右 - 左 - 1
- 高 = 下 - 上 - 1
- flag = False
- Select Case 查找方向
- Case 0 '从左到右,从上到下.顺序
- For y = 0 To 高: For x = 0 To 宽
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 1 '从左到右,从下到上.顺序
- For y = 高 To 0 Step -1: For x = 0 To 宽
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 2 '从右到左,从上到下.顺序
- For y = 0 To 高: For x = 宽 To 0 Step -1
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 3 '从右到左,从下到上.顺序
- For y = 高 To 0 Step -1: For x = 宽 To 0 Step -1
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 4 '从上到下,从左到右.顺序
- For x = 0 To 宽: For y = 0 To 高
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 5 '从上到下,从右到左.顺序
- For x = 宽 To 0 Step -1: For y = 0 To 高
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 6 '从下到上,从左到右.顺序
- For x = 0 To 宽: For y = 高 To 0 Step -1
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- Case 7 '从下到上,从右到左.顺序
- For x = 宽 To 0 Step -1: For y = 高 To 0 Step -1
- If 颜色相似度 = 0 Then
- If 屏幕像素数据(2, x, y) = Red And 屏幕像素数据(1, x, y) = Green And 屏幕像素数据(0, x, y) = Blue Then
- flag = True: GoTo 结束
- End If
- Else
- If 颜色相似度判断(屏幕像素数据(2, x, y), 屏幕像素数据(1, x, y), 屏幕像素数据(0, x, y), _
- Red, Green, Blue, 颜色相似度) = True Then
- flag = True: GoTo 结束
- End If
- End If
- Next: Next
- End Select
- 结束:
- If flag = True Then
- 结果x = x + 左
- 结果y = y + 上
- End If
- FoundX = 结果x
- FoundY = 结果y
- End Sub
-
-
按键精灵2014脚本:
调用例子:
- Dim x, y, 颜色
- 颜色 = "0000FF"
- Call Plugin.TULING.FindColor(0, 0, 1024, 768, 颜色, 0, 1, x, y)
- TracePrint x & "," & y //输出找到的坐标
未完待续……
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。