OpenCV基础代码模块

  本篇博文记录下在学习中常用的关于OpenCV-Python的一些相关知识点,以及一些代码模块。

OpenCV基础操作

 1、cv2.imread(img_path, flags)

  根据完整的文件路径读取图片,返回np.array。第二个参数表示读取类型,待选参数包括:

  • cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,可用1作为实参替代
  • cv2.IMREAD_GRAYSCALE:读入灰度图片,可用0作为实参替代
  • cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道,可用-1作为实参替代
import cv2
cv2.imread('图片1.jpg')
array([[[239, 241, 241],
        [239, 241, 241],
        [239, 241, 241],
        ...,
       [[195, 198, 196],
        [195, 198, 196],
        [195, 198, 196],
        ...,
        [213, 214, 212],
        [213, 214, 212],
        [213, 214, 212]],
        ...,
        [212, 213, 211],
        [212, 213, 211],
        [212, 213, 211]]], dtype=uint8)
cv2.imread('图片1.jpg').shape
(512, 512, 3)

  这里我们注意到这个返回的图片的维度,分别表示(h, w, 通道数),因为cv2是将一个图片根据像素按照左上角为坐标0切割了整个图片,因此第一个维度表示行(在图片中表示的就是纵坐标),第二个维度表示列(在图片中表示就是横坐标),因此shape的结果第一个维度数量(数组的行数)其实对应的是图片的高。第三个维度表示通道数,如果是彩色图像那么是3维的,可以这么理解:RGB是三维数组可以表示任意一种颜色,那么对于一个像素点,就可以用三个数字来表示,因此如果读取的是彩色图像,每个像素点将会是3维的,因此(0,0,0)=10,表示(0,0)这个像素点的R数值为10,(0,0,1)=20,表示(0,0)这个像素点的G数值为:20....

  我们可以看看如果以黑白图像来读取,那么得到的结果将会是二维的。

import cv2
cv2.imread('图片1.jpg', 0)
array([[241, 241, 241, ..., 254, 254, 254],
       [241, 241, 241, ..., 254, 254, 254],
       [241, 241, 241, ..., 254, 254, 254],
       ...,
       [198, 198, 198, ..., 212, 212, 212],
       [197, 197, 197, ..., 213, 213, 213],
       [197, 197, 197, ..., 212, 212, 212]], dtype=uint8)
cv2.imread('图片1.jpg', 0).shape
(512, 512)

 2、cv2.imwrite(save_path,img_array,num)

  用于图片的保存,也就是把一个img_array的数组以图片的形式保存下来,这里的save_path表示的是保存的路径,要注意路径中需要有img_name.jpg(.png)注意需要加上后缀。第三个参数,主要是对保存为特定的文件后缀(.jpeg,.png)起压缩图片的作用,常用有以下两种形式:

  • cv2.imwrite('1.jpeg',img, [cv2.IMWRITE_JPEG_QUALITY,  图片质量])  图片质量:0~100数字越高图像质量越好
  • cv2.imwrite('1.png',img, [cv2.IMWRITE_PNG_COMPRESSION,  压缩等级])  压缩等级:从0到9 压缩级别越高图像越小
img = cv2.imread('图片1.jpg')
cv2.imwrite('1.jpeg', img, [cv2.IMWRITE_JPEG_QUALITY, 10])
cv2.imwrite('2.jpeg', img, [cv2.IMWRITE_JPEG_QUALITY, 20])
cv2.imwrite('3.jpeg', img, [cv2.IMWRITE_JPEG_QUALITY, 70])

  最后出来的三张图片如下效果:

  PS:cv2.IMWRITE_PNG_COMPRESSION好像压缩得不够狠程度1,和程度2,差别只有在图像大小上有1K左右差别。。。肉眼看不出来,不知道怎么回事。还有就是一定要注意如果不是指定的文件后缀,是不会起作用的。

 3、cv2.imshow(wname,img)

  使用弹窗显示图片(其中第一个参数是字符串窗口的名字,第二个参数是np.array)。

  一般都需要跟一个 cv2.waitKey(0),意思是等待键盘输入之后消失,如果把0换成其他数字则表示等待多少秒后消失。cv2.waitKey顾名思义等待键盘输入,单位为毫秒,即等待指定的毫秒数看是否有键盘输入,若在等待时间内按下任意键则返回按键的ASCII码,程序继续运行。若没有按下任何键,超时后返回-1。参数为0表示无限等待。不调用waitKey的话,窗口会一闪而逝,看不到显示的图片。

 4、img.copy()

  复制一个图片的备份,类型是np.array(不共用内存)

 5、 cv2.copyMakeBorder(img, top, bottom, left,  right , borderType)

  对图片进行padding。第2-4个参数top, bottom, left, right 分别表示在不同方向上进行扩展的像素长度。最后一个参数borderType表示采用哪种方式进行扩展,常用的有以下4种方式:

  • cv2.BORDER_REPLICATE:根据图像的边界的像素值,向外扩充图片
  • cv2.BORDER_REFLECT:把靠近边界的同等长度的像素翻折出去(轴对称)
  • cv2.BORDER_CONSTANT:填充固定颜色,这个参数存在需要在后面添加一个参数 value = [0,0,0](填充黑色)
  • cv2.BORDER_WRAP:不知道怎么解释,cdefgh|abcdefgh|abcdefg 

  6、img.reshape([h,w,通道])

  这个函数其实跟np中的reshape是一样的,要注意的是像素点必须一个不多,一个不少的才能分配,比如原图像的尺寸是(250,4,3),那么reshape的之后的图像h*w*通道=250*4*3

 7、cv2.resize(InputArray,  OutputArray,  fx, fy, interpolation)

  • InputArray:img的array形式,想要改变的图片

  • OutputArray:是一个元组类型,表示输出图片(改变之后图片)的尺寸(w, h)

  • fx, fy:沿x轴,y轴的缩放系数
  • interpolation:插值的方法

    • INTER_NEAREST:最近邻插值
    • INTER_LINEAR:双线性插值(默认设置)
    • INTER_AREA:使用像素区域关系进行重采样
    • INTER_CUBIC:4x4像素邻域的双三次插值
    • INTER_LANCZOS4:8x8像素邻域的Lanczos插值

   这个和上一个函数reshape的差别就是不用再考虑像素总数的关系。可以任意改造成我们喜欢的形状,不过要注意图像的比例可能被改变,会被拉大或者被拉瘦这种。

 

 8、cv2.line(img, pt1, pt2, color, thickness, lineType, shift) 

  在图片img中画出中起始点为pt1,终点为pt2的一条直线。

  • pt1,pt2:分别代表起始点和终点,格式为(x,y)

  • color:代表所画直线的颜色,用BGR格式,例如(255,0,0)表示蓝色

  • thickness:画笔的粗细,线宽(int)。若是-1表示画封闭图像,如填充的圆。
  • lineType:线条的类型可选:cv2.LINE_8,cv2.LINE_4,cv2.LINE_AA,(具体没差别,不是什么虚线,实线的差别)

cv2.line(canvas, (0, 0), (300, 300), (255,0,0),3) 

 

 

 

OpenCV常用

 1、根据图像比例进行padding

  在一些图像处理中我们常常需要把图片的格式或者长宽进行该格式化,但是不同的图片长宽比例不同,直接用resize可能会导致图像一些特征变形,因此常常采用padding的方法来把保持原图的比例大小并且扩充到我们需要的格式。下面提供一个代码来实现这个事情。

def resize_img_keep_ratio(img,target_size):
    '''
    将图片padding成给定目标大小
    img:np.arrary
    target_size:[h, w]
    '''
    old_size = img.shape[0:2]    # 获取图片h,w
    #ratio = min(float(target_size)/(old_size))
    ratio = min(float(target_size[i])/(old_size[i]) for i in range(len(old_size))) # 获得原始高宽和目标高宽的比例
    new_size = tuple([int(i*ratio) for i in old_size])  # 保持了原图的h和w的比例
    img = cv2.resize(img,(new_size[1], new_size[0]))    # 输入参数要求size = (w, h)
    pad_w = target_size[1] - new_size[1]  # 需要padding的大小
    pad_h = target_size[0] - new_size[0]  # pad_h和pad_肯定有一个是0
    top,bottom = pad_h//2, pad_h-(pad_h//2)  # 意味着只对长或者只对宽进行padding
    left,right = pad_w//2, pad_w -(pad_w//2)
    img_new = cv2.copyMakeBorder(img,top,bottom,left,right,cv2.BORDER_CONSTANT,value=[255,255,255])  # padding成白色,这里padding的方法有很多参见前文
    return img_new

  2、仿射变换

   在视觉任务下游处理中,比如在车牌检测中,我们的车牌图片需要时正视图才能被CRNN模型准确的识别出结果,但是很多情况我们都无法拍摄到车牌的正视图,因此如果我们能定位到车牌的四个点,再通过某种仿射变化,把倾斜的车牌变成正视图的车牌,这样就能很好的匹配下游任务了。

import cv2
import numpy as np

def warp_per_image(img, pst1, shape):
    """
    仿射变换
    :param img:
    :param pst1: 顺序 [ [左上角点]  [右上角点]  [右下角点]  [左下角点] ]  真实图片的对应点
    :param pst2: 顺序 [ [左上角点]  [右上角点]  [右下角点]  [左下角点] ]  希望的对应点
    :param shape: 图片的【w,h】
    :return:
    """
    pst2 = [0, 0], [shape[0], 0], [shape[0], shape[1]], [0, shape[1]]

    pst1 = np.float32(pst1)
    pts2 = np.float32(pst2)
    M = cv2.getPerspectiveTransform(pst1, pts2)
    dst = cv2.warpPerspective(img, M, shape)
    return dst

  比如下图就是通过定位到车牌四个角的点,再将其仿射变换成[w,h]=[440,140]的形状

 

 

 

 

 

 

 

参考资料:

https://blog.csdn.net/weixin_44015965/article/details/109547129

https://blog.csdn.net/qq_36560894/article/details/105416273

https://blog.csdn.net/li_l_il/article/details/83218838

posted @ 2021-07-21 15:08  Circle_Wang  阅读(174)  评论(0编辑  收藏  举报