之前在 Udacity 的计算机视觉工程师的课程里接触了不少 OpenCV 的操作,但还是想更加系统的学一下,所以在通过 《Learning OpenCV 3 Computer Vision with Python》和其他资源进一步熟悉 OpenCV,前面这本书在出版社 Packt 的主页上支持免费下载,所以喜欢看原版书的可以自行下载。在这里零散的记录一些容易被忽略的要点,以备查看:
- 除非使用 cv2.IMREAD_UNCHANGED 图片读入模式,否则
imread()
都会忽略 α 通道的透明度信息,与此同时,imwrite()
要求被输出的图片必须是 grascyle 或者通道按照 BGR 排列的图片。
- OpenCV 进行图片读取时,如果没有成功获取到图片,并没有任何提醒,而后续操作也可能会出现很奇异的报错,因此比较安全的做法是通过代码确定图片读入成功:
if img is None:
raise Exception("Please check the availability of the image file!")
- 在视频读取中,实例化 VideoCapture() 后的 get() 方法不是总能得到准确的 FPS 值,因此需要通过其他方式,如手动计时来进一步获得这个信息
cap = cv2.VideoCapture(0) # Here 0 is the index of the video camera
# Check if the camera opened successfully
if cap.isOpened() == False:
print("Unable to read camera feed")
# Get the frame size information for output usage
frame_width = int(cap.get(3)) # frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(4)) # frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Get the frame per second information
fps = cap.get(cv2.CAP_PROP_FPS)
cv2.waitKey(0) & 0xFF
:在某些系统中,单纯的使用cv2.waitKey()
时的返回值可能会超过正常 ASCII 中的取值范围,而 0xFF 对应的二进制数值的最后 8 位为 11111111,因此通过cv2.waitKey(0) & 0xFF
可以确保返回的是 8 位的比特值Erosion & Dilation: 二者为最基本的形态相关的操作,二者的输入都需要是binary image,Erosion 会移除物体边缘的像素以缩小被处理物体的尺寸,而 dilation 则会增加被处理物体的尺寸:
# Create a binary thresholded image
retval, binary = cv2.threshold(gray, 225, 255, cv2.THRESH_BINARY_INV)
dilation = cv2.dilate(binary, kernel, iterations=1)
erosion = cv2.erode(binary, kernel, iterations=1)
- Opening VS Closing: Opening 在 erosion 后执行 dilation 操作,用于降噪;而 Closing 则是先执行 dilation 后再进行 erosion 操作,用于关闭图片中的孔洞或移除黑色斑点
opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
-
RGB to Gray: 在 OpenCV 中,RGB 图片转换成灰度图片时,同一个位置上的像素的强度计算方法为:
gray = rgb[0, :, :] * 0.299 + rgb[1, :, :] * 0.587 + rgb[2, :, :] * 0.114
直方统计
直方图 Histogram 这一统计工具由于操作简单而又可以提供很多的信息,因而在计算机视觉中被得以广泛的应用。例如:通过对于图片上不同通道或灰度图片的强度 Intensity 的直方图统计可以获得关于图片色彩分布和对比度情况的信息,在 HOG, Histogram of Oriented Gradient 算法中通过统计图片中各个子区域的梯度信息来完成特征构建。
Histograms Equalization
当通过直方图对图片强度信息统计后会经常发现图片本身的强度信息并不是均匀分布的,而是在不同的强度区域有所集中。为了增加图片的对比度 contrast,可以通过执行直方均衡来改善图片的质量。这一变换更为一般的关系为:
- g(i, j) = αf(i, j) + β,其中 α 调节对比度情况,而 β 调节亮度情况
img = cv2.imread('moutain.jpg', 0)
# Global histogram equalization
equalized = cv2.equalizeHist(img)
combined = np.hstack((img, equalized))
plt.imshow(combined, cmap='gray')
plt.xticks([]), plt.yticks([]);
执行 Histogram Equalization 前后的图片效果如下:
CLAHE (Contrast Limited Adaptive Histogram Equalization)
前述 HE 操作是针对图片的全局信息进行操作的,在实际使用中,有很多情况下仅考虑局部信息的直方均衡会取得更好的效果。CLAHE 在使用中仅考虑预先设定的图片区域(默认 8x8)内的直方统计情况,并且当某一区域内的对比度超过算法的设定值(默认 40)时,会对造成这个区域过高对比度的像素强度执行裁剪 clip ,最后再通过对分块区域的边缘进行插值过渡。
img = cv2.imread('moutain',0)
# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
clahed = clahe.apply(img)
Gamma 校正
Gamma 校正通过对输入图片的像素施加非线性变换而修改图片像素的亮度,也正是由于这个非线性变换关系,使得 Gamma 校正相比于对比度调整更加不容易造成饱和现象,其变换关系为:
- O = (I / 255)gamma x 255
When γ < 1, the original dark regions will be brighter and the histogram will be shifted to the right whereas it will be the opposite with γ > 1.