Bootstrap

OpenCV-Python入门 上

图像的读取和显示

#cv.imread(filename[,flags]) -> retval函数读取图像
#filename表示文件路径,[]内的参数表示可选,flag指定了读取图像的方式,也可以不填,flag指定了读取图像的方式
#cv.IMREAD_COLOR:加载彩色图像,任何图像的透明度都会被忽略,它是默认标志
#cv.IMREAD_GRAYSCALE:以灰度模式加载图像
#cv.IMREAD_UNCHANGED:加载图像,包括 alpha 通道
#可以简单地分别传递整数 1、0 或-1,而不是这三个 flag

#cv.imshow(winname, mat) -> None函数在窗口中显示图像,窗口自动适应图像的大小
#winname表示窗口标题,mat 表示图像对象

#cv.waitKey(0) 表示一直等待,直到任意一个键盘操作
#cv.waitKey(1000) #表示等待1000毫秒即1秒

def show_img():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.imshow("japanese",image)
    cv.waitKey(0)
    cv.destroyAllWindows() #回收资源

图像色彩空间转换

注意:彩色图像 OpenCV 用的 BGR 模式,但是 Matplotlib 显示用的 RGB 模式。因此如果图像用 OpenCV 加载,则 Matplotlib 中彩色图像将无法正常显示。
图像色彩空间.JPG

  • RGB色彩空间,设备独立,RGB是计算机显示器的标准支持色彩系统
  • HSV色彩空间,对计算机友好,区分各种色彩
  • YCrCb, Y分量表示信息,CrCb可以被压缩
  • RGB的取值范围0~255
  • HSV取值范围:
    H:0~180(OpenCV中)
    SV:0~255
    从一个色彩空间转换到另外一个色彩空间会造成信息传递与损失
#cv.cvtColor(src, code[,dst[,dstCn]])->dst
#src表示输入图像,类型有CV_8U和CV_32F
#code表示:COLOR_BGR2RGB=4,COLOR_BGR2GRAY=6,COLOR_GRAY2BGR=8,COLOR_BGR2HSV=40
def color_space_demo():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.imshow("wicher", 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()

图像对象的创建与赋值

  • 图像宽高 image.shape
  • 图像深度 image
  • 图像数据类型 image.dtype
  • 图像通道 image.shape
  • OpenCV-Python支持的数据类型:
    np.uint8
    np.float32
    np.int32
    np.int64
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

图像像素的读写操作

def visit_pixel_demo():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.imshow("wicher", 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()

图像算术操作

#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表示图像
#加法,保证不越界:saturate(src1 + src2)->0~255

def arithmetic_demo():
    image1 = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    image2 = np.zeros_like(image1)
    image2[:,:] = (110,0,250)
    cv.imshow("image1", image1)
    cv.imshow("image2", image2)
    added = cv.add(image1, image2)
    cv.imshow("added", added)
    cv.waitKey(0)
    cv.destroyAllWindows()

def arithmetic_demo1():
  image1 = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    image2 = np.zeros_like(image1)
    image2[:,:] = (110,0,250)
    cv.imshow("image1", image1)
    cv.imshow("image2", image2)
    added = cv.add(image1, image2)
    cv.imshow("added", added)
    cv.waitKey(0)
    cv.destroyAllWindows()
  • mask参数:
    mask.JPG

滚动条操作

  • Callback基本流程
    Callback基本流程.JPG
#cv.namedWindow(winname[,flags])->None
#参数: winname表示窗口标题
#参数flags支持的flag有:
#WINDOW_NORMAL – 可以调整窗口大小
#WINDOW_AUTOSIZE – 根据图像大小自动适应,不可调
#WINDOW_KEEPRATIO – 可以保持比例窗口,调整大小

#调整图像亮度
#RGB值表示亮度,RGB(0,0,0)黑色->RGB(255,255,255)白色
#add函数支持图像+图像与图像+常量方式
#subtract函数支持图像+图像与图像+常量方式
#通过他们可以修改图像的亮度

def trackbar_callback(pos):
    print(pos)

def trackbar_demo():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.namedWindow("trackbar_demo", cv.WINDOW_AUTOSIZE)
    cv.createTrackbar("Lightness", "trackbar_demo", 0, 200, trackbar_callback)
    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()

键盘响应操作

  • cv.waitKey( [, delay] ) -> retval
    delay如果没有声明或者delay=0,表示一直阻塞
    delay大于0,表示阻塞指定毫秒数
    retval返回的对应键盘键值,注意:在不同的操作系统中可能会有差异!典型的retval = 27是ESC按键
  • 检查返回键值,根据不同键值完成不同操作,推荐使用if-elif-else, switch-case方式python3.10支持
#按ESC推出,按1显示HSV图像,按2显示YCrCb,按3显示RGB图像,按0恢复原图BGR显示

def keyboard_demo():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.namedWindow("keyboard_demo", cv.WINDOW_AUTOSIZE)
    cv.imshow("keyboard_demo", image)
    while True:
        c = cv.waitKey(10)
        if c == 27:
            break
        elif c == 48:
            cv.imshow("keyboard_demo", image)
        elif c == 49:
            hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
            cv.imshow("keyboard_demo", hsv)
        elif c == 50:
            ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
            cv.imshow("keyboard_demo", ycrcb)
        elif c == 51:
            rgb = cv.cvtColor(image, cv.COLOR_BGR2RGB)
            cv.imshow("keyboard_demo", rgb)
    cv.waitKey(0)
    cv.destroyAllWindows()

自带颜色表操作

  • 查找表LUT(Look Up Table)
    查找表.JPG
  • Gamma校正
    gamma校正.JPG
  • OpenCv中LUT支持(OpenCV提供的colormap)
    opencv中的lut支持.JPG
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()
#建立查找表
def lut_demo1():
    lut1 = np.zeros((256), dtype=np.uint8)
    gamma = 0.7
    for i in range(256):
        print(i, "--", np.log(i / 255.0 + 1e-5))
        lut1[i] = int(np.exp(np.log(i / 255 + 1e-5) * gamma) * 255.0)
    print(lut1)
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.imshow("input", image)
    cv.namedWindow("lut-demo", 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] = (lut1[b], lut1[g], lut1[r])
    cv.imshow("lut-demo", image)
    cv.waitKey(0)
    cv.destroyAllWindows()
#自定义查找表
def lut_demo2():
    lut2 = np.zeros((256, 1, 3), dtype=np.uint8)
    gamma = 0.7
    for i in range(256):
        print(i, "--", np.log(i / 255.0 + 1e-5))
        c = int(np.exp(np.log(i / 255.0 + 1e-5) * gamma) * 255.0)
        lut2[i, 0] = (c, c, c)
    print(lut2)
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.imshow("input", image)
    cv.namedWindow("lut-demo", cv.WINDOW_AUTOSIZE)
    dst = cv.LUT(image, lut2)
    cv.imshow("lut-demo", dst)
    cv.waitKey(0)
    cv.destroyAllWindows()
#系统查找表
def lut_demo3():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    dst = cv.applyColorMap(image, cv.COLORMAP_PINK)
    cv.imshow("japanese-pink", dst)
    cv.waitKey(0)
    cv.destroyAllWindows()

通道分离与合并

  • 分离函数
    通道分离函数cv.split(m[, mv]) ->mv
    m表示输入图像,必须是多通道图像,mv表示输出的
  • 合并与混合
    cv.merge(mv[, dst])->dst
    mv表示各个通道
    cv.mixChannels(src, dst, fromTo)->dst
    src表示输入多通道图像,fromTo表示通道索引,dst表示返回结果
  • 通道阈值
    cv.inRange(src, lowerb, upperb[, dst])->dst
    其中src是输入图像,Lowerb是低值,Upperb是高值
    dst = (lowerb < src < upperb)
def channel_demo():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.namedWindow("channel-demo", cv.WINDOW_AUTOSIZE)
    cv.imshow("channel-demo", image)
    mv = cv.split(image)
    cv.imshow("mv[0]", mv[0   ])
    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()

图像像素值统计信息

均值.JPG

  • cv.mean(src[, mask])->retval
  • cv.meanStdDev(src[, mean[, stddev[, mask]]]) ->mean, stddev
  • cv.minMaxLoc(src[, mask]) ->minVal, maxVal, minLoc, maxLoc
    src表示输入图像,mask表示计算区域
    mean, stddev, minVal, maxVal分别表示均值,标准方差,最小与最大
  • 均值应用:调整对比度
    Dst = (Src-mean) * contrast + mean
    调整对比度.JPG
def stats_demo():
    image = cv.imread(r"..\dataset\Image\The_Witcher_Lover.jpg")
    cv.imshow("wicher", 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-wicher", cv.convertScaleAbs(result))

    result = sub_m * 2.0
    result = result[:, :] + (bgr_m[0], bgr_m[1], bgr_m[2])
    cv.imshow("high-contrast-wicher", cv.convertScaleAbs(result))

    cv.waitKey(0)
    cv.destroyAllWindows()

图像几何形状绘制

  • 相关函数cv.line()、cv.circle()、cv.rectangle()、cv.ellipse()、cv.putText()
    相关参数解释:img表示输入图像,color表示颜色,如(255, 0,0)表示蓝色,thickness表示线宽, 大于0表示绘制,小于0表示填充,lineType表示渲染模式, 默认LINE_8, LINE_AA表示反锯齿
    putText 默认只支持英文,org表示文字起始坐标点,fontFace表示字体类型,fontScale表示字体大小
  • 计算文本区域大小函数getTextSize (text, fontFace, fontScale, thickness)
    text表示文本信息,fontFace表示字体类型,fontScale表示字体大小,thickness表示线宽
    返回文本信息区域大小,与字体的基线baseline位置
def draw_demo():
    canvas = np.zeros((512, 512, 3), dtype=np.uint8)
    cv.rectangle(canvas, (100, 100), (300, 300), (0, 0, 255), 2, 8)
    cv.circle(canvas, (250, 250), 50, (255, 0, 0), 4, 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)
    cv.destroyAllWindows()

canvas.JPG

def draw_demo():
    #动态合理显示文本区域
    font_color = (140, 199, 0)
    canvas = np.zeros((512, 512, 3), dtype=np.uint8)
    cv.rectangle(canvas, (100, 100), (300, 300), font_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() 

canvas1.JPG

随机数与随机颜色

  • Numpy中的随机函数:random.randint(low, high=None, size=None, dtype=int)
    Low表低值,high表示高值,size表示维度,dtype表示类型
  • 随机噪声图的生成cv.randn(dst, mean, stddev)
    生成目标图像dst,噪声均值mean,噪声方差stddev
    cv.randn(canvas, (40, 200, 140), (10, 50, 10))
def random_demo():
    canvas = np.zeros((512, 512, 3), dtype=np.uint8)
    #random draw
    while True:
        b, g, r = np.random.randint(0, 256, size=3)
        x1 = np.random.randint(0, 512)
        x2 = np.random.randint(0, 512)
        y1 = np.random.randint(0, 512)
        y2 = np.random.randint(0, 512)
        cv.rectangle(canvas, (x1, y1), (x2, y2), (int(b), int(g), int(r)), -1, 8)
        cv.imshow("canvas", canvas)
        c = cv.waitKey(50)
        if c == 27:
            break
        cv.rectangle(canvas, (0, 0), (512, 512), (0, 0, 0), -1, 8)

    cv.randn(canvas, (120, 100, 140), (30, 50, 20))
    cv.imshow("noise image", canvas)
    cv.waitKey(0)
    cv.destroyAllWindows()

多边形填充与绘制

  • cv.fillPoly(img, pts, color[, lineType[, shift[, offset]]]) ->img
    填充多边形(可以一次绘制多个)
  • cv.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]] ) ->img
    绘制多边形(可以一次绘制多个)
    pts表示一个或者多个点集,color表示颜色,thickness表示线宽,注意:必须大于0,lineType 表示渲染方式
  • 点集支持
    点集支持.JPG
def poly_demo():
    canvas = np.zeros((512, 512, 3), dtype=np.uint8)
    pts = []
    pts.append((100, 100))
    pts.append((200, 50))
    pts.append((280, 100))
    pts.append((290, 300))
    pts.append((50, 300))
    pts = np.asarray(pts, dtype=np.int32)
    print(pts.shape)

    pts2 = []
    pts2.append((300, 300))
    pts2.append((400, 250))
    pts2.append((500, 300))
    pts2.append((500, 500))
    pts2.append((250, 500))
    pts2 = np.asarray(pts2, dtype=np.int32)
    print(pts2.shape)

    cv.polylines(canvas, [pts, pts2], True, (0, 255, 255), 4, 8)
    cv.fillPoly(canvas, [pts, pts2], (255, 0, 0), 8, 0)
    cv.imshow("poly-demo", canvas)
    cv.waitKey(0)
    cv.destroyAllWindows()
;