OpenCV StudyNote

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()

insert image description here

Image color space conversion

Commonly used color spaces:

insert image description here

  • ​ 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()

insert image description here

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()

insert image description here

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()

insert image description here

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()

insert image description here

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()

insert image description here

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()

insert image description here

Built-in color table operation

Lookup Table (LUT)

Exchange space for time, avoid double calculation and save calculation time

insert image description here

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=kEr=255Elog(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返回图像

insert image description here

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()

insert image description here

insert image description here

insert image description here

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()

insert image description here

image statistics

Pixel Value Statistics

Five dimensions/channels of the image (x, y, z, r, g, b)

  • average
cv.mean(src[, mask]	) ->retval

insert image description here

  • 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()

insert image description here

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)

insert image description here

# 变成填充的
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)

insert image description here

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()

insert image description here

Guess you like

Origin blog.csdn.net/weixin_64632836/article/details/128314644