学习opencv的第一步当然是显示图像,先拿我母校的图片试试水==。显示图像主要靠cv.imread()加载图像,通过cv.imshow()来显示图像代码如下
import cv2
import cv2 as cv
src = cv.imread("road.jpg")
cv.imshow('road', src)
cv.waitKey(0)
cv.destroyAllWindows()
cv.waitKey(0)是为了让图像无限期等待下一次敲击键而不会立刻关掉,由于我的图片太大,我加入cv.namedWindow使得图片的大小可以通过外框的拉伸实现,如下
src = cv.imread("road.jpg")
cv.namedWindow('road',cv.WINDOW_NORMAL)
cv.imshow('road', src)
cv.waitKey(0)
cv.destroyAllWindows()
其实cv.namedWindow是先生成了一个窗口,然后把图片扔进去,主要在于后面的参数。默认其实是cv.WINDOW_AUTOSIZE,我们这里改为cv.WINDOW_NORMAL使得窗口的大小可以调节,然后显示图片。
另外一种方式用resize重新设置图片的大小,再把图片导出来,如下
src = cv.imread("road.jpg")
pic_resize = cv2.resize(src, None, fx=0.2, fy=0.2, interpolation=cv2.INTER_AREA)
cv.imshow('road', src)
cv.waitKey(0)
cv.destroyAllWindows()
src = cv.imread("road.jpg",0)
可以读入灰度图像
加上imwrite保存图像并退出,可以使用waitkey去判断按键再考虑要不要保存,如下
src = cv.imread("road.jpg",0)
pic_resize = cv2.resize(src, None, fx=0.2, fy=0.2, interpolation=cv2.INTER_AREA)
cv.imshow('road', pic_resize)
k = cv.waitKey(0)
if k == 27: # 等待ESC退出
cv.destroyAllWindows()
elif k == ord('s'): # 等待关键字s,保存和退出
cv.imwrite('road_gray.png', pic_resize)
也可以用Matplotlib库来显示图片,但是不能显示彩色的,好像是opencv加载的方式和Matplotlib不一致
plt.imshow(src, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([]) # 隐藏 x 轴和 y 轴上的刻度值
plt.show()
一般来说彩色的图像的点会由R,G,B三种值构成,而灰度图像就只会显示灰度值,可以通过坐标访问对应位置的像素值。
以刚才的图像为例,进行坐标点[100,100]的像素值读取可以如下写
px = src[100, 100]
print("pixel of the point [100,100] is", px)
当图像为彩色时,得到的结果如下,额这里数组的排序是BGR,要注意不能搞混了。
pixel of the point [100,100] is [11 27 26]
为灰色时即前面说到的imread显示灰度图像然后再读像素值
pixel of the point [100,100] is 29
可以用src.shape返回图像的行列,src.size返回像素总数,src.dtype返回数据类型
print("图像形状:", src.shape, '\n像素总数:', src.size, '\n数据类型:', src.dtype)
src.shape结果是行,列,通道数元组,结果如下
图像形状: (4032, 2688, 3)
像素总数: 32514048
数据类型: uint8
接下来是修改像素的方式,
最简单的修改像素的方式就是直接对图像某个点进行像素修改,直接用数组赋值的方式就可以了。。。即
src[100, 100] = [255, 255, 255]
print(src[100, 100])
当然可以只访问单个颜色的像素值,
blue = src[200, 200, 0]
当然,访问单个像素值一般用array.item(),修改用array.itemset()会比较好。
偶尔图像处理会关注一些特殊区域,我们称为roi区域,为了减少图像处理的负担,我们可以选取感兴趣的部分进行处理,一般来说ROI区域的选取可以直接用坐标来获取如
ROIArea = img[280:340, 330:390]
我这里简单地使用了按键回调的机制写了个画框图来选取ROI区域的机制如下,按esc退出图像
import cv2
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
src = cv.imread("road.jpg")
pic_resize = cv2.resize(src, None, fx=0.2, fy=0.2, interpolation=cv2.INTER_AREA)
selecting = False # 如果按下鼠标,则为真
ix_start = 0
iy_start = 0
ROI_corner = np.empty(4)
# 先初始化roi为整个图像
ROI_Area = pic_resize[0:pic_resize.shape[0], 0:pic_resize.shape[1]]
def ROIselect(event,x,y,flags,param):
global ix_start, iy_start, selecting, ROI_corner
if event == cv.EVENT_LBUTTONDOWN:
selecting = True
ix_start, iy_start = x, y
elif event == cv.EVENT_LBUTTONUP:
if selecting == True :
# 让矩形可以反向伸缩
ROI_corner[0] = min(ix_start, x)
ROI_corner[1] = min(iy_start, y)
ROI_corner[2] = max(ix_start, x)
ROI_corner[3] = max(iy_start, y)
print("框的坐标为:\n")
print("矩形框左上角坐标:")
print(ROI_corner[0], ROI_corner[1])
print("矩形框右下角坐标:")
print(ROI_corner[2], ROI_corner[3])
cv.rectangle(pic_resize, (int(ROI_corner[0]), int(ROI_corner[1])), (int(ROI_corner[2]), int(ROI_corner[3])), (0, 255, 0), 2)
ROI_Area = pic_resize[ROI_corner[0]:ROI_corner[1], ROI_corner[2]:ROI_corner[3]]
selecting = False
cv.namedWindow('image')
cv.setMouseCallback('image', ROIselect)
while(1):
cv.imshow('image', pic_resize)
if cv.waitKey(20) & 0xFF == 27:
break
cv.destroyAllWindows()
这里发现cv.rectangle的坐标参数只接收int的数值,所以转换了一下, ROI_Area 先是被初始化为整幅图像,然后变为框里的部分,效果如图
矩形框左上角坐标:
220.0 375.0
矩形框右下角坐标:
391.0 523.0
顺便加个显示roi坐标的字
text_display1 = 'roi zone:' + str(ROI_corner[0]) + ':' + str(ROI_corner[2]) + ','
text_display2 = str(ROI_corner[1]) + ':' + str(ROI_corner[3])
cv.putText(pic_resize, text_display1, (int(ROI_corner[2]) + 10, int(ROI_corner[3]) + 10), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1, cv.LINE_AA)
cv.putText(pic_resize, text_display2, (int(ROI_corner[2]) + 10, int(ROI_corner[3]) + 30), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1, cv.LINE_AA)