前言:
欢迎来到本博客
目前正在进行 OpenCV技能树的学习,OpenCV是学习图像处理理论知识比较好的一个途径,至少比看书本来得实在。本专栏文章主要记录学习OpenCV的过程以及对学习过程的一些反馈记录。感兴趣的同学可以一起学习、一起交流、一起进步。
下面框架图主要是OpenCV入门技能树总共有27个知识点,其中包括了8个大章的学习内容,如果感兴趣的可以进一步学习博主写的关于OpenCV的专栏【通俗易懂OpenCV(C++版)详细教程】:
支持:如果觉得博主的文章还不错或者您用得到的话,可以悄悄关注一下博主哈,如果三连收藏支持就更好啦!这就是给予我最大的支持!
题目:Hello World
以下 Hello World 程序中,能够正确执行下述操作的是?
·读取目录下lena图片
·显示lena图像窗口
·等待用户输入任意按键后关闭窗口
·销毁所有窗口
解析:
import cv2
if __name__=='__main__':
img = cv2.imread("lena.png")
cv2.imshow("lena",img)//名称在前,变量在后
cv2.waitKey(0)
cv2.destroyAllWindows()
题目:极简OpenCV环境安装
·OpenCV 的官方教程里提供了各平台的安装教程:
https://docs.opencv.org/4.x/df/d65/tutorial_table_of_content_introduction.html
·但是最便利的方式是安装 opencv-python ,安装命令如下:
pip install opencv-python
·在 Python 中打印出使用的 OpenCV 版本,正确的代码是?
解析:
import cv2
print(cv2.__version__)
1、题目:图像像素颜色
·认识颜色空间,OpenCV 常用的颜色空间有:RGB颜色空间、HSV颜色空间、Lab颜色空间。
·以下选项中【不正确】打印像素(100,100)处颜色空间分量名字的是?
解析:
import numpy as np
import cv2 as cv
if name == 'main':
img = cv.imread('lena.png', cv.IMREAD_COLOR)
px = img[100, 100]
print(f'red:{px[0]}, green:{px[0]}, blue:{px[0]}')//这行代码有误
OpenCV读图片默认通道是排列BGR
2、题目:图片黑客帝国化
·黑客帝国的图片风格偏绿色,任意图片的每个像素(r,g,b)经过公式转换后即可获得一张“黑客帝国风格图片”:
r = r^(3/2)
g = r^(4/5)
b = r^(3/2)
·我们对lena图片也做黑客帝国风格化处理:
·框架代码如下:
import numpy as np
import cv2
import math
def hacker(img):
# TODO(You): 请在此添加代码
if __name__ == '__main__':
img_origin = cv2.imread('lena.png', cv2.IMREAD_COLOR)
img = cv2.imread('lena.png', cv2.IMREAD_COLOR)
print(img.size)
print(img.shape)
hacker(img)
print('显示图片,请按任意键退出')
numpy_horizontal_concat = np.concatenate((img_origin, img), axis=1)
cv2.imshow('Lena图片黑客帝国化', numpy_horizontal_concat)
cv2.waitKey()
cv2.destroyAllWindows()
·以下选项是对函数 def hacker(img) 的实现,请选出实现【有错】的选项:
解析:
def hacker(img):
height, width, channels = img.shape
for i in range(0, width):
for j in range(0, height):
b, g, r = img.item((i, j))
hack_b = int(math.pow(b/256.0, 3/2) * 256)
hack_g = int(math.pow(g/256.0, 4/5) * 256)
hack_r = int(math.pow(r/256.0, 3/2) * 256)
img.itemset((i, j), (hack_b, hack_g, hack_r))
另: item和itemset函数区别
3、题目:梅西足球轨迹
使用 OpenCV 可以方便的剪切粘贴图像上的区域。例如下图是梅西在踢足球:
实现代码如下,需要补全TODO部分:
import cv2
import numpy as np
if __name__ == '__main__':
img = cv2.imread('ball.jpg', cv2.IMREAD_COLOR)
start = [493, 594]
end = [112, 213]
ball = img[start[0]:start[1], end[0]:end[1]]
x_step = 101
y_step = 10
for i in range(-1, 4):
# TODO(You): 请在此实现代码
cv2.imshow("ball_continue", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
解析:
x_offset = x_stepi
y_offset = y_stepi
img[start[0]-y_offset:start[1]-y_offset, end[0]+x_offset:end[1]+x_offset] = ball
注意:图像中,一般情况下左上角为坐标轴的(0,0)点,X是水平方向(往右为正,往左为负),Y是竖直方向(往下为正,往上为负)。值得注意的是,起点图片是图二左下角第一哥足球,并非图一的原始足球位置。
从图中可以看出足球轨迹,在Y的方向是往上(为负),在X的方向是往右(为正)。
python
中data[ 1 : 10, 2:30 ]
中 :是表示一个序列,逗号前 1:10表示X的范围从1到10, 2:30表示Y的范围是2到30;
x_step
所在的线是平行于X轴的水平线;
y_step
所在的直线是平行于Y轴的竖直线;
所以,x_step是Y方向上的增加量;y_step是X方向上的增加量;足球轨迹在Y的方向是往上(为负),即start[0]-y_offset:start[1]-y_offset
,在X的方向是往右(为正),即end[0]+x_offset:end[1]+x_offset
。
1、题目:甲壳虫乐队
一只甲壳虫想组个乐队,但是临时找不到队友。
请使用 OpenCV 读取下面的彩色甲壳虫图片 'bug.jpg',帮助他变身灰色甲壳虫,然后完成组队。
显示甲壳虫乐队并写入到 'bug_band.jpg',以下实现正确的是?
解析:
import numpy as np
import cv2
if name == 'main':
bug_img = cv2.imread("bug.jpg") #读取图像
'''将彩色三通道转换为单通道的灰度图,其转换原理为:
GRAY = B * 0.114 + G * 0.587 + R * 0.299'''
bug_img_gray = cv2.cvtColor(bug_img, cv2.COLOR_BGR2GRAY)
'''COLOR_GRAY2BGR 将单通道的灰度图转换为三通道,这是为了后面的图像合并。
COLOR_GRAY2BGR的原理:R = G = B = GRAY; A = 0;
R,G,B相等时,图像会显示为灰值,不相等时颜色会偏向于较大的基色;'''
bug_img_gray_by_BGR_space = cv2.cvtColor(bug_img_gray, cv2.COLOR_GRAY2BGR)
''' concatenate 合并两副图像,要求两幅图像大小一致,通道一致。
连接方向(轴向),
axis=0时,垂直连接;
axis=1时,水平连接;
axis=None时,扁平输出,即把二维矩阵中的每个元素横向顺序依次放到一个一维矩阵(列表)中'''
bug_img_concat = np.concatenate(
(bug_img, bug_img_gray_by_BGR_space),
axis=1
)
cv2.imwrite("bug_band.jpg", bug_img_concat)
cv2.imshow('甲壳虫乐队', bug_img_concat)
cv2.waitKey(0)
cv2.destroyAllWindows()
2、题目:早起的鸟儿有虫吃
早起的鸟儿不但有虫吃,还可以照镜子。请你帮助鸟儿们跟镜像合影。
这是跟镜像合影的效果:
基本的实现代码如下,合影每10帧采样一次:
import numpy as np
import cv2
if __name__ == '__main__':
cap = cv2.VideoCapture('birds.mp4')
out = ...
# TODO(You): 请在此正确创建待保存的目标mp4文件`out`
i = 0
while(cap.isOpened()):
ret, bird_frame = cap.read()
if bird_frame is None:
break
bird_flip_frame = cv2.flip(bird_frame, 0)
bird_concat_frame = np.concatenate(
(bird_frame, bird_flip_frame),
axis=1
)
cv2.imshow('bird_concat_frame', bird_concat_frame)
if i % 10 == 0:
out.write(bird_concat_frame)
i += 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
out.release()
cap.release()
cv2.destroyAllWindows()
解析:
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
out = cv2.VideoWriter(
'birds_concat.mp4',
cv2.VideoWriter_fourcc('mp4v'),fps,(width2, height))
3、题目:甲壳虫的Base64之旅
如下的一只甲壳虫,我们希望把它编码成 Base64,再从Base64解码出来。代码框架如下:
以下对两个函数实现正确的是?
import numpy as np
import cv2
import base64
def img_to_base64(img):
# TODO(You):
def img_from_base64(img_base64):
# TODO(You):
if __name__ == '__main__':
img = cv2.imread('bug.jpg')
img_base64 = img_to_base64(img)
img = img_from_base64(img_base64)
cv2.imshow('img_decode', img)
cv2.waitKey()
cv2.destroyAllWindows()
解析:
def img_to_base64(img):
return base64.b64encode(cv2.imencode('.jpg', img)[1]).decode()
def img_from_base64(img_base64):
jpg_original = base64.b64decode(img_base64)
jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
img = cv2.imdecode(jpg_as_np, flags=1)
return img
4、题目:矩形涂鸦画板
编写一个矩形涂鸦画板,实现功能:
·鼠标左键按下拖动绘制矩形,鼠标左键弹起时完成绘制
·按'c'键清空画板
·按'ESC'键退出
基本框架代码如下:
import numpy as np
import cv2 as cv
from random import randint
class Painter:
def __init__(self) -> None:
self.mouse_is_pressed = False
self.last_pos = (-1, -1)
self.width = 300
self.height = 512
self.img = np.zeros((self.width, self.height, 3), np.uint8)
self.window_name = 'painter'
self.color = None
def run(self):
print('画板,拖动鼠标绘制矩形框,按ESC退出,按c键清空画板')
cv.namedWindow(self.window_name)
cv.setMouseCallback(
self.window_name,
lambda event, x, y, flags, param: self.on_draw(
event, x, y, flags, param
)
)
while True:
cv.imshow(self.window_name, self.img)
k = cv.waitKey(1) & 0xFF
if k == ord('c'):
self.clean()
elif k == 27:
break
cv.destroyAllWindows()
def on_draw(self, event, x, y, flags, param):
# TODO(You): 请正确实现画板事件响应,完成功能
def clean(self):
cv.rectangle(self.img, (0, 0), (self.height, self.width), (0, 0, 0), -1)
def begin_draw_rectangle(self, pos1, pos2):
if self.color is None:
self.color = (randint(0, 256), randint(0, 256), randint(0, 256))
cv.rectangle(self.img, pos1, pos2, self.color, -1)
def end_draw_rectangle(self, pos1, pos2):
self.color = None
if __name__ == '__main__':
p = Painter()
p.run()
以下正确实现鼠标事件,完成画板绘制逻辑的代码是?
解析:
pos = (x, y)
if event == cv.EVENT_LBUTTONDOWN:
self.mouse_is_pressed = True
self.last_pos = pos
elif event == cv.EVENT_MOUSEMOVE:
if self.mouse_is_pressed == True:
self.begin_draw_rectangle(self.last_pos, pos)
elif event == cv.EVENT_LBUTTONUP:
self.end_draw_rectangle(self.last_pos, pos)
self.mouse_is_pressed = False
注意:使用变量mouse_is_pressed
去控制,鼠标按下为mouse_is_pressed = true
;鼠标移动时当mouse_is_pressed==true
时才会绘制;当鼠标抬起时,mouse_is_pressed = false
停止绘制。