Open CV learning
Image reading and display
Grayscale Image - Single Channel
Color image - three channels (B, G, R)
general steps
import cv2 as cv # 导入OpenCV支持(cv2是包的名称不是版本号)
import numpy as np # 所有图像数据都是以 numpy 数组方式存储
imread(filename[,flags]) # imread 函数,读取图像
# filename 表示文件路径, []内可以不填
imshow(winname, mat) # imshow 函数,显示图像
# winname 表示窗口标题, mat 表示图像对象
# 加载通道顺序
Display and waiting time
cv.wajitKey(0)
Indicates to wait until any keyboard operation
cv.waitKey(1000)
Indicates waiting for 1000ms or 1s
If not added, the picture will flash by
example
import cv2 as cv
import numpy as np
def show_image():
image = cv.imread("E:/data/lena.jpg")
cv.imshow("input", image)
cv.waitKey(0)
cv.destroyAllWindows()
show_image()
Image color space conversion
Commonly used color spaces:
- HSV
- Value range H: 0 ~ 180, SV: 0 ~ 255
- RGB
- Standard supported color systems for computer monitors
- Color space device independent
- Value range 0~255
- YCrCb
- • Y component represents information, CrCb can be compressed
Image color conversion
-
Convert from one color space to another
-
Information Transmission and Loss
-
Process reversible and irreversible
Functions and parameters
cv.cvtColor(src,code[,dst[,dstCn]])->dst
# src表示输入图像, 类型CV_8U(np.uint8字节类型)、CV_32F(np.float32浮点数类型)
code means:
cv::COLOR_BGR2RGB = 4 # 通道交换 cv::COLOR_BGR2GRAY = 6 # 彩色到灰度 cv::COLOR_GRAY2BGR = 8 # 灰度到彩色(信息损失不可逆) cv::COLOR_BGR2HSV = 40 # 可以双线转换
Example:
import cv2 as cv
import numpy as np
def color_space_demo():
image = cv.imread("lena.jpg")
cv.imshow("lena", image)
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("hsv", hsv)
cv.imshow("ycrcb", ycrcb)
cv.waitKey(0)
cv.destroyAllWindows()
color_space_demo()
Image Object Creation and Assignment
Image Object Properties
- Image width and height image.shape
- image depth image
- Image data type image.dtype
- image channel image.shape
- type of data
- e.g. uint8
- np.float32
- np.int32
- np.int64
Numpy packet functions
All image data in opencv-python are numpy array
*• numpy.array(object, dtype=None, , copy=True, order=‘K’, subok=False, ndmin=0, like=None)
-
object array
-
dtype data type
*•numpy.zeros(shape, dtype=float, order=‘C’, , like=None)
-
array dimension
-
dtype data type
*•numpy.asarray(a, dtype=None, order=None, , like=None)
-
array object
-
dtype data type
•numpy.reshape(a, newshape, order=‘C’)
-
array dimension
-
dtype data type
import numpy as np
np.array([[1, 2],[3, 4]], dtype=np.uint8)
create image
• np.zeros -> creates a black background image
• np.zeros_like -> Creates a black background image of the same size as the input image
• np.ones creates an image where all pixels have a value of 1
image assignment
• Image assignment is to assign values to numpy arrays
•m = np.zeros((3, 3, 3), dtype=uint8)
•m[:] = 255
• Create an array m, and then assign a value of 255 (white)
•m[:] = (255,0,0)
• Create an array m, and then assign the value (255,0,0) blue
code demo
def numpy_demo():
m1 = np.array([[2,3], [4, 5]], dtype=np.uint8)
print(m1)
m2 = np.ones((4,4,3), dtype=np.uint8)
print(m2)
m2[:] = (255, 0, 0)
print(m2)
m3 = np.zeros((4,4,3),dtype=np.uint8)
print(m3)
m3[:]=255
print(m3)
numpy_demo()
C:\use\anaconda\envs\openvino\python.exe C:/use/E/Desktop/cv/opencv/test.py
[[2 3]
[4 5]]
[[[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]
[1 1 1]][[1 1 1]
[1 1 1]
[1 1 1]
[1 1 1]]]
[[[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]][[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]][[255 0 0]
[255 0 0]
[255 0 0]
[255 0 0]][[255 0 0]
[255 0 0]
[255 0 0]
[255 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 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
[[[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]][[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]][[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]][[255 255 255]
[255 255 255]
[255 255 255]
[255 255 255]]]Process ended with exit code 0
def numpy_demo():
black = np.zeros((512, 512, 3), dtype=np.uint8)
black[:,0:255] = 255
h,w,c = black.shape
print(h,w,c)
cv.imshow("black", black)
cv.waitKey(0)
cv.destroyAllWindows()
numpy_demo()
Image pixel read and write operations
Pixel access and traversal
-
The essence of pixel traversal is numpy array access
-
Suppose variable image
-
Get image dimension information: image.shape
-
Image access pixels: image[row, col]
-
Image assignment pixels: image[row, col] = (b,g,r)
Pixel reading and writing
-
b, g, r = image[row, col]
-
image[row, col] = (255-b, 255-g, 255-r)
-
Read and write pixelated, grayscale images:
-
pv = image[row, col]
-
image[row, col] = 255-pv
example
def visit_pixel_demo():
image = cv.imread("lena.jpg")
cv.imshow("lina", image)
h, w, c = image.shape
for row in range(h):
for col in range(w):
b, g, r = image[row, col]
# 反色
image[row, col] = (255 - b, 255 - g, 255 - r)
cv.imshow("visited", image)
cv.waitKey(0)
cv.destroyAllWindows()
visit_pixel_demo()
Pixel Arithmetic Operations
arithmetic operations
- add
- reduce
- take
- remove
support function
-
cv.add(src1, src2[, dst[, mask[, dtype]]]) ->dst
-
cv.subtract(src1,src2[,dst[,mask[,dtype]]])->dst
-
cv.multiply(src1,src2[,dst[,scale[,dtype]]])->dst
-
cv.divide(src1, src2[, dst[, scale[, dtype]]])->dst
src1 & src2 represent images
Addition, guaranteed not to cross the boundary: saturate(src1 + src2)-》0~255
More than 255 takes 255, less than 0 takes 0
- mask parameter
- The mask area is added and subtracted, and the other areas are zero
example
def arithmetic_demo():
image1 = cv.imread("lena.jpg")
h, w, c = image1.shape
image2 = np.zeros_like(image1)
image2[:,:] = (110, 0, 250)
mask = np.zeros((h, w), dtype=np.uint8)
mask[100:200,100:200] = 1;
cv.imshow("img1", image1)
cv.imshow("img2", image2)
added = cv.add(image1, image2, mask = mask)
cv.imshow("added", added)
cv.waitKey(0)
cv.destroyAllWindows()
arithmetic_demo()
scroll bar operation
event response function
typedef void(* cv::TrackbarCallback) (int pos, void *userdata)
完成事件响应函数的声明与实现
// pos 滑块所在位置 userdata 用户数据
# 完成事件响应函数的声明与实现
def trackbar_callback (pos):
print(pos)
create window function
cv.namedWindow(winname [, flags]) -> None
# 参数: winname表示窗口标题
# 参数flags支持的flag有:
# WINDOW_NORMAL – 可以调整窗口大小
# WINDOW_AUTOSIZE – 根据图像大小自动适应,不可调
# WINDOW_KEEPRATIO – 可以保持比例窗口,调整大小
Adjust image brightness
• RGB values represent brightness
• RGB(0, 0,0) black -> RGB(255,255,255) white
• The add function supports image+image and image+constant methods
•The subtract function supports image+image and image+constant methods
• Through them you can modify the brightness of the image
•Dynamic adjustment, modify the constant value based on the scroll bar, realize dynamic modification of image brightness and refresh display
• Create image windows
• Create a scrollbar component
• Display image in window
• Drag the scroll bar to modify image brightness
code demo
def trackbar_callback(pos):
print(pos)
def trackbar_demo():
image = cv.imread("E:/data/butterfly.jpg")
cv.namedWindow("trackbar_demo", cv.WINDOW_KEEPRATIO)
# 创建滚动条
cv.createTrackbar("lightness", "trackbar_demo", 0, 200, trackbar_callback)
cv.imshow("trackbar_demo", image)
while True:
# 获取该窗口滚动条的位置
pos = cv.getTrackbarPos("lightness", "trackbar_demo")
image2 = np.zeros_like(image)
image2[:, :] = (np.uint8(pos), np.uint8(pos), np.uint8(pos))
# 提升亮度
result = cv.add(image, image2)
# 降低亮度
# result = cv.subtract(image, image2)
cv.imshow("trackbar_demo", result)
c = cv.waitKey(1)
if c == 27:
break
cv.waitKey(0)
cv.destroyAllWindows()
trackbar_demo()
Keyboard Response Actions
keyboard response event
cv.waitKey( [, delay] ) ->retval
If delay is not declared or delay=0, it means that
delay is greater than 0, and it means that the corresponding keyboard key value returned by retval is blocked for the specified number of milliseconds
. Note: there may be differences in different operating systems!
Typical retval = 27 is the ESC key
Respond to different keyboard actions
via python's select statement
It is recommended to use if-elif-else; switch-case mode python3.10 support
if <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
...
else:
<statement(s)>
example
image = cv.imread("E:/data/butterfly.jpg")
cv.namedWindow("keyboard_demo", cv.WINDOW_AUTOSIZE)
cv.imshow("keyboard_demo", image)
while True:
c = cv.waitKey(10)
# 按ESC退出
if c == 27:
break
# 按0回复原图BGR显示
elif c == 48:
cv.imshow("keyboard_demo", image)
# 按1显示HSV图像
elif c == 49:
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
cv.imshow("keyboard_demo", hsv)
# 按2显示YCrCb
elif c == 50:
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("keyboard_demo", ycrcb)
# 按3显示RGB图像
elif c == 51:
rgb = cv.cvtColor(image, cv.COLOR_BGR2RGB)
cv.imshow("keylboard_demo", rgb)
cv.waitKey(0)
cv.destroyAllWindows()
Built-in color table operation
Lookup Table (LUT)
Exchange space for time, avoid double calculation and save calculation time
Gamma correction
G a m m a = k ∗ E r = 255 ∗ E l o g ( p ( x , y ) / 255 ) ∗ g a m m a Gamma =k*E^r=255*E ^ {log(p(x,y)/255)*gamma} Gamma=k∗Er=255∗Elog(p(x,y)/255)∗gamma
• The formula p(x, y) represents the pixel value of the input image, and the value of gamma ranges from 0.05 to 5
• The range of pixel values is between 0 and 255, and each value corresponds to an output value. In this way, a lookup table LUT can be established first
•According to the input pixel value as index, the value after gamma correction is directly mapped and read in the LUT
• For images of size 256x256, calculation comparison:
• Do not use table lookup to calculate gamma - 65536 times,
• Calculation of gamma using lookup table – 256 times
cv.applyColorMap(src, colormap[, dst]) ->dst
# 第一个参数输入图像
# 第二个参数是颜色表
# dst返回图像
example
def lut_demo():
cv.namedWindow("lut-demo", cv.WINDOW_NORMAL)
lut = [[255, 0, 255], [125, 0, 0], [127, 255, 200], [200,127, 127], [0, 255, 255]]
m1 = np.array([[2, 1, 3, 0], [2, 2, 1, 1], [3, 3, 4, 4], [4,4,1,1]])
m2 = np.zeros((4, 4, 3), dtype=np.uint8)
for i in range(4):
for j in range(4):
index = m1[i, j]
m2[i, j] = lut[index]
cv.imshow("lut-demo", m2)
cv.waitKey(0)
cv.destroyAllWindows()
lut2 = np.zeros((256), dtype=np.uint8)
gamma = 0.7
for i in range(256):
print(i, "--", np.log(i / 255.0))
lut2[i] = int(np.exp(np.log(i/255.0) * gamma) * 255.0)
print(lut2)
image = cv.imread("E:/data/butterfly.jpg")
dst = cv.LUT(image, lut2)
cv.imshow("butterfly-gamma", dst)
cv.imshow("input", image)
cv.namedWindow("butterfly-gamma", cv.WINDOW_AUTOSIZE)
h, w, c = image.shape
for row in range(h):
for col in range(w):
b, g, r = image[row, col]
image[row, col] = (lut2[b], lut2[g], lut2[r])
cv.imshow("butterfly-gamma", image)
# 自定义查找表
lut3 = np.zeros((256, 1, 3), dtype=np.uint8)
for i in range(256):
print(i, "--", np.log(i / 255.0))
c = int(np.exp(np.log(i/255.0) * gamma) * 255.0)
lut3[i, 0] = [c, c, c]
print(lut3)
dst = cv.LUT(image, lut3)
cv.imshow("butterfly-gamma", dst)
# 系统查找表
dst = cv.applyColorMap(image, cv.COLORMAP_PINK)
cv.imshow("butterfly-pink", dst)
cv.waitKey(0)
cv.destroyAllWindows()
lut_demo()
Channel sorting and merging
A three-channel image can be divided into three single-channel images
RGB/HSV color channels
separated into individual channels
Use different thresholds to extract masks for different channels
Extract information from one of the channels
separation function
cv.split(m[, mv]) ->mv
# m表示输入图像,必须是多通道图像
# mv表示输出的
Merge and Mix
cv.merge(mv[, dst])->dst
# mv表示各个通道:多通道分类出来的单通道数组,每一个元素代表一个单通道图像
cv.mixChannels(src, dst, fromTo)->dst
mixChannels([src], [dst], fromTo)
# src表示输入多通道图像
# fromTo表示通道索引
# dst表示返回结果
# 使用时一定要注意src和dst外面还有一层括号,如果使用时没得到想要的效果,可以考虑检查此,此处括号不加并不会报错。
channel threshold
cv.inRange( src, lowerb, upperb[, dst]) -> dst
# 其中src是输入图像
# Lowerb是低值
# Upperb是高值
# dst = (lowerb < src < upperb) 二值图像
# 只取范围之间的像素
code demo
def channel_splits():
image = cv.imread("E:/data/butterfly.jpg")
cv.namedWindow("butterfly", cv.WINDOW_AUTOSIZE)
cv.imshow("butterfly", image)
mv = cv.split(image)
dst = np.zeros_like(image)
# BGR2RGB
cv.mixChannels([image], [dst], fromTo = [0, 2, 1, 1, 2, 0])
cv.imshow("mix-channels", dst)
mask = cv.inRange(image, (43, 46, 100), (128, 200, 200))
cv.imshow("inRange", mask)
cv.waitKey(0)
cv.destroyAllWindows()
channel_splits()
image statistics
Pixel Value Statistics
Five dimensions/channels of the image (x, y, z, r, g, b)
- average
cv.mean(src[, mask] ) ->retval
- variance
cv.meanStdDev(src[, mean[, stddev[, mask]]]) ->mean, stddev
- extremum
cv.minMaxLoc(src[, mask]) ->minVal, maxVal, minLoc, maxLoc
• src represents the input image, mask represents the calculation area
•mean, stddev, minVal, maxVal represent mean, standard deviation, minimum and maximum respectively
mean application
•Dst = (Src-mean) * contrast+mean
def stats_demo():
image = cv.imread("E:/data/butterfly.jpg")
cv.imshow("butterfly", image)
bgr_m = cv.mean(image)
sub_m = np.float32(image)[:, :] - (bgr_m[0], bgr_m[1], bgr_m[2])
result = sub_m * 0.5
result = result[:, :] + (bgr_m[0], bgr_m[1], bgr_m[2])
cv.imshow("low-contrast-butterfly", cv.convertScaleAbs(result))
result = sub_m * 2.0
result = result[:, :] + (bgr_m[0], bgr_m[1], bgr_m[2])
cv.imshow("high-contrast-butterfly", cv.convertScaleAbs(result))
cv.waitKey(0)
cv.destroyAllWindows()
stats_demo()
Image Geometry Drawing
- line, rectangle, circle, ellipse
- Text (Chinese is not supported)
related functions
cv.line()
cv.circle()
cv.rectangle()
cv.ellipse()
cv.putText
Calculate text area size:
getTextSize(
text, #表示文本信息
fontFace, #表示字体类型
fontScale, #表示字体大小
thickness # 表示线宽
)
# 返回文本信息区域大小,与字体的基线baseline的位置
Related parameters:
img input image
color color * (matching the number of img channels) * (255,0,0) means blue
thickness means line width, greater than zero means drawing, less than zero means filling
lineType indicates the rendering mode, the default is LINE_8
Text drawing:
putText only supports Chinese by default
org indicates the starting coordinate point of the text
fontFace indicates the font type
fontScale represents the font size
example
def draw_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8) # 512 * 512的三通道图像
cv.rectangle(canvas, (100, 100), (300, 300), (0, 0, 255), 2, 8)
cv.circle(canvas, (250, 250), 50, (255, 0, 0), 2, cv.LINE_8)
cv.line(canvas, (100, 100), (300, 300), (0, 255, 0), 2, 8)
cv.putText(canvas, "OpenCV-Python", (100, 100), cv.FONT_HERSHEY_SIMPLEX,1.0, (255, 0, 255), 2)
cv.imshow("canvas", canvas)
cv.waitKey(0)
# 变成填充的
def draw_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8) # 512 * 512的三通道图像
cv.rectangle(canvas, (100, 100), (300, 300), (0, 0, 255), -2, 8)
cv.circle(canvas, (250, 250), 50, (255, 0, 0), 2, cv.LINE_8)
cv.line(canvas, (100, 100), (300, 300), (0, 255, 0), 2, 8)
cv.putText(canvas, "OpenCV-Python", (100, 100), cv.FONT_HERSHEY_SIMPLEX,1.0, (255, 0, 255), 2)
cv.imshow("canvas", canvas)
cv.waitKey(0)
def draw_demo():
canvas = np.zeros((512, 512, 3), dtype=np.uint8) # 512 * 512的三通道图像
# 动态合理显示文本
front_color = (140, 199, 0) # 土耳其蓝
cv.rectangle(canvas, (100, 100), (300, 300), front_color, 2, 8)
label_txt = "OpenCV-Python"
font = cv.FONT_HERSHEY_SIMPLEX
font_scale = 0.5
thickness = 1
(fw, uph), dh = cv.getTextSize(label_txt, font, font_scale, thickness)
cv.rectangle(canvas, (100, 100-uph-dh), (100+fw, 100), (255,255, 255), -1, 8)
cv.putText(canvas, label_txt, (100, 100 - dh), font, font_scale, (255, 0, 255), thickness)
cv.imshow("canvas", canvas)
cv.waitKey(0)
cv/destroyAllWindows()