【OpenCV技能树】——OpenCV基础


前言

😊😊😊欢迎来到本博客😊😊😊

  目前正在进行 OpenCV技能树的学习,OpenCV是学习图像处理理论知识比较好的一个途径,至少比看书本来得实在。本专栏文章主要记录学习OpenCV的过程以及对学习过程的一些反馈记录。感兴趣的同学可以一起学习、一起交流、一起进步。🌟🌟🌟

  下面框架图主要是OpenCV入门技能树总共有27个知识点,其中包括了8个大章的学习内容,如果感兴趣的可以进一步学习博主写的关于OpenCV的专栏【通俗易懂OpenCV(C++版)详细教程】

在这里插入图片描述

🎁🎁🎁支持:如果觉得博主的文章还不错或者您用得到的话,可以悄悄关注一下博主哈,如果三连收藏支持就更好啦!这就是给予我最大的支持!😙😙😙


一、OpenCV基础

1.1 OpenCV 简介

  题目: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()

1.2 OpenCV安装(python版)

  题目:极简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.3 图像的基本操作

  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的方向是往右(为正)。

  pythondata[ 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.4 IO与GUI

  
  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 停止绘制。


🚶🚶🚶 今天的文章就到这里啦~
喜欢的话,点赞👍、收藏⭐️、关注💟哦 ~
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cqy阳

预祝上岸,感谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值