opencv简单图形数组识别
使用opencv的数组排列做一些简单图形得判断(不使用轮廓命令),比如矩形,圆形,三角形,横线,竖线;
首先我们考虑从图像生成的数组进行判断,将图片转化成灰度,然后从图像不等于255的点是否连续出现入手,创建一个图片75x50(横75高50,小一点图片方便看数据),选择1px的画笔,否则容易出现误差
image2 = cv2.imread("yuan.jpg", 0)
print("image2",image2)
用这两句命令即可打印出图片的数组,但是显示不完全,加上下面的命令使数据显示完整
import cv2
import numpy as np
np.set_printoptions(threshold=np.inf)
image2 = cv2.imread("yuan.jpg", 0)
pixel_matrix = np.array(image2)
cv2.imshow("flower", image2)
cv2.waitKey()
cv2.destroyAllWindows()
print("image2",pixel_matrix)
得到数组:
由此发现,我们得到的数组并不像预想的精确,该是一个黑色像素的地方可能连接出现好几个接近255的值,可能会影响判断。
此处也要考虑线所占的像素数,我们先预知线段的粗细,也就是每个点所占的像素点,在win自带的画图软件中,线段粗细是会显示几个像素点的(鼠标停留一下),可选择1px,这样比较不会影响识别结果,那如果我们不是自己画线段,无法预知线段的粗细,我们可以在代码里加上一句(只是线段,其他形状容易产生误差),
for i in range(0, image2.shape[0]):
a = 0
for j in range(0, image2.shape[1]):
if image2[i][j] != 255
a = a + 1
print(a) #如果线段的点占8px,这里会输出8次1,因为这里的break是跳出j的循环,也就是一旦进入if,这一横排就不再扫描了,而粗线横竖都占8px,所以向下还会扫到一次直到8次
break
if a>10:
print("heng")
break
这是灰度图的数组,下面我们来看二值图像的显示数组,二值图像(Binary Image)是一种特殊类型的图像,其中每个像素只有两种可能的灰度值,通常是0和255。这两个值分别代表黑色和白色,因此二值图像也被称为黑白图像或单色图像。在二值图像中,不存在灰度的中间值,只有纯黑和纯白两种颜色,使得图像具有明显的对比效果。
cv2.threshold这个命令有两个返回值1,实际使用的阈值(通常大于240就会被赋值255,但实际情况也可能被调整),2,二值化后图像,_, binary表示省略第一个返回值,第二个赋给binary
cv2.THRESH_BINARY_INV:阈值处理的模式。THRESH_BINARY_INV 表示反向二值化,即大于阈值(阈值一般为240)的像素设为0,小于等于阈值的像素设为255
_, binary = cv2.threshold(image2, 240, 255, cv2.THRESH_BINARY_INV)
print("binary",binary)
输出结果可以看出,经过二值反向变化,数组清晰很多,圆的顶点并非一个点而是一个线段,中部一行会只有两个点是255
下面我们可以根据输出数值找到各个轮廓的特征,加以判断
先将每一行255的点的个数找出来压在一个列表
list=[]
for i in range(0, binary.shape[0]):
a = 0
for j in range(0, binary.shape[1]):
if binary[i][j] == 255:
a = a + 1
list.append(a)
print(list)
对比几个轮廓的区别:(我这里是75x50,线条都是1px)
三角:
[0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
圆形:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
横线:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
竖线:
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
矩形:
[0, 0, 0, 0, 0, 0, 0, 0, 38, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
识别图片的代码如下:
if sum(1 for x in list if x != 0) == 1: #如果是横线则列表里只有一个数字遍历列表 my_list 中的每个元素 x。如果元素 x 不等于 0(即 x != 0),则生成一个 1。
print("heng")
s=sum(1 for x in list if x == 2) #如果是矩形算出列表里多少个2
print(sum(1 for x in list if x == 2))
for i in range(0,len(list)):
if list[i] == 1 and list[i + 1] == 1: #竖线的话会连续出现1
print("shu")
break
elif list[i] == 2 and list[i - 1] == 1: #三角形1,2连续出现
print("Triangle")
break
elif list[i]==2 and list[i-1]==list[i+s] and list[i-1]-list[i]>3: #矩形连续2的两头的数字相等,s为2的个数也就是连续出现2的左边的数字
print("Rectangle")
break
elif list[i]==2 and list[i-1]-list[i]<3:
print("Circle")
break