当前位置:   article > 正文

Chapter1 - 像素(Pixel)操作

np.zeros(src.shape,src.dtype)

Chapter1 - 像素(Pixel)操作

  1. import cv2 as cv
  2. import numpy as np
  3. src = cv.imread("opencv.png")

一、改变像素值

  1. # copy image, deep copy
  2. img_copied = np.copy(src)
  3. # change value
  4. img_changed = img_copied
  5. img_copied[100:200, 200:300, :] = 255
  6. # both `img_changed` and `img_copied` change.
  7. cv.imshow("img_changed", img_changed)
  8. cv.imshow("img_copied", img_copied)
  9. cv.waitKey(0)
  10. cv.destroyAllWindows()

运行结果

img_changed
img_changed

img_copied
img_copied

关于复制np.copy()

  • src的类型是numpy.ndarray,即放置同类型的元素的多维数组。所以“复制图片”要用np.copy()

  • python有直接引用、浅复制、深复制

  • 对于列表等可循环结构,即python list

    • b = a是直接引用,指向同一个对象,a改变,b也跟着改变
    • b = a.copy()是浅复制;a改变,b也改变
    • b = a.deepcopy()是深复制;a、b相互独立
  • numpy listpython list不同:

    • img_copied = np.copy(src)深拷贝;即src改变,但img_copied不变;
    • img_changed = img_copied是直接引用;img_copied改变,img_changed也要改变;

二、通过像素值新建图像

  1. # create image
  2. img_created = np.zeros(src.shape, src.dtype) # value:all zero, Black
  3. cv.imshow("img_created", img_created)
  4. img_1 = np.zeros([512,512], dtype=np.uint8)
  5. img_1[:,:] = 127 # set gray value: 127
  6. img_2 = np.ones([512,512,3], dtype=np.uint8)
  7. img_2[:,:,0] = 255 # "B":255,"G"="R"=1, Blue
  8. cv.imshow("gray image: img_1", img_1)
  9. cv.imshow("R\'s value=255: img_2", img_2)
  10. cv.waitKey(0)
  11. cv.destroyAllWindows()

注意

读取彩色图片时,会有三层,这三层代表的RGB是颠倒的,也就是BGR

  • img[:,:,0]代表B
  • img[:,:,1]代表G
  • img[:,:,2]代表R

改变RGB的值就意味着能对图像的色彩进行操作,那么我们下面使用数组的方式,把对应位置的BGR值做一下变化,观察一下效果:

  1. # read and write pixels
  2. img_copied = np.copy(src)
  3. row, column, channel = img_copied.shape
  4. print("row: %d, column: %d, channel: %d" % (row, column, channel))
  5. for i in range(row):
  6. for j in range(column):
  7. b, g, r = img_copied[i, j]
  8. b = 255 - b
  9. g = 255 - g
  10. r = 255 - r
  11. img_copied[i, j] = [b, g, r]
  12. cv.imshow("read and write pixels", img_copied)
  13. cv.waitKey(0)
  14. cv.destroyAllWindows()
row: 610, column: 570, channel: 3

运行结果

read and write pixels

在处理610×570这样一个小型图像时,反应时间便明显变长;

为了提高速度,一方面需要更好的设备,另一方面上述代码最好改写成支持CUDA加速;

两个图像的像素之间也是可以做算术运算的(只要不超出范围即可),比如下面这个例子:

  1. # pixel arithmetic operations
  2. img_1 = cv.imread("test0.jpg")
  3. img_2 = cv.imread("test1.jpg")
  4. result = np.zeros(shape=[4,img_1.shape[0],img_1.shape[1],img_1.shape[2]], dtype=img_1.dtype)
  5. for i in range(4):
  6. result[i][:,:,:] = np.zeros(shape=[img_1.shape[0],img_1.shape[1],img_1.shape[2]], dtype=img_1.dtype)
  7. cv.add(img_1, img_2, result[0])
  8. cv.imshow("add_result", result[0])
  9. cv.subtract(img_1, img_2, result[1])
  10. cv.imshow("sub_result", result[1])
  11. cv.multiply(img_1, img_2, result[2])
  12. cv.imshow("mul_result", result[2])
  13. cv.divide(img_1, img_2, result[3])
  14. cv.imshow("div_result", result[3])
  15. cv.waitKey(0)
  16. cv.destroyAllWindows()

算数运算的操作比较简单,这里不再详述;

为了存储每次算数运算的结果,可以每次都新建变量--初始化--承接结果;为了缩减初始化的工作量,新建了result这个4维矩阵;

result从宏观上看,可以认为是4个元素的list,每个元素都是一个图像类型(3维);这种提取过程需要会。

三、像素值的逻辑运算

除了算术操作,我们也可以进行逻辑操作(logical operation),常见的有三种:

  • cv.bitwise_add() 逻辑与;
  • cv.bitwise_or() 逻辑或;
  • cv.bitwise_not() 逻辑否;
  • cv.bitwise_xor() 异或;同为0,异为1

当然,不仅可以对两张图片做逻辑操作,也可以只对一张图片做逻辑操作,不过只能做not运算,图中的白色会变成黑色;而其他逻辑操作,如and等会报错;

下面,我们新建矩形和圆形图片,对这两张图片进行逻辑操作,两种图形的用法分别如下:

cv.rectangle(img, (x,y), (x+h,y+h), (b,g,r), line_thickness)

  • (x,y)(x+h,y+h)分别对应了左上和右下角;这样的话,第一个点的坐标应该小于第二个点;但是如果第一个点的坐标大于第二个点,会被认为是左下和右上角

  • (b,g,r)是矩形四条边的BGR数值;注意是BGR而非RGB;如果这里只写一个255,代表B=255,G=R=0,也就是蓝色;

  • line_thickness是边的厚度;如果是负数,如-1,表示填充整个矩形,填充的颜色是上面线条的颜色

cv.circle(img, (x,y), r, (b,g,r), thickness)

  • (x,y)是圆的圆心坐标,r是半径;
  • 其他的和上面矩形类似;
  1. # create rectangle
  2. img_1 = np.zeros(shape=[400,400,3], dtype=np.uint8)
  3. cv.rectangle(img_1, (25,25), (375,375), 255, -1)
  4. cv.imshow("rectangle", img_1)
  5. # create circle
  6. img_2 = np.zeros(shape=[400,400,3], dtype=np.uint8)
  7. cv.circle(img_2, (200,200), 200, 255, -1)
  8. cv.imshow("circle", img_2)
  9. # make logical operations
  10. dst1 = cv.bitwise_and(img_1, img_2)
  11. dst2 = cv.bitwise_or(img_1, img_2)
  12. dst3 = cv.bitwise_xor(img_1, img_2)
  13. dst4 = cv.bitwise_not(src)
  14. cv.imshow("add", dst1)
  15. cv.imshow("or", dst2)
  16. cv.imshow("xor", dst3)
  17. cv.imshow("not to picture", dst4)
  18. cv.waitKey(0)
  19. cv.destroyAllWindows()

运行结果

logical operation

not to picture

四、伪彩色applyColorMap函数

使用OpenCV的预定义的颜色映射来将灰度图像伪彩色化;显示的效果类似于颜色滤镜;

应用领域:空间中的行星和其他物体的灰度图像是采用伪彩色来显示细节,并对不同颜色的不同材质对应的区域进行标记。比如下面对冥王星处理的图片:

ColorMap

下面,我们对于图片使用伪彩色效果:

  1. img_cool = cv.applyColorMap(src, cv.COLORMAP_COOL)
  2. img_jet = cv.applyColorMap(src, cv.COLORMAP_JET)
  3. cv.imshow("colormap.cool", img_cool)
  4. cv.imshow("colormap.jet", img_jet)
  5. cv.waitKey(0)
  6. cv.destroyAllWindows()

运行结果

colormap.cool&jet

五、图像通道的分离cv.split()和合并cv.merge()

  1. # channel seperation
  2. B, G, R = cv.split(src)
  3. print("分离后的维数:", B.shape)
  4. cv.imshow("Split Blue", B)
  5. cv.imshow("Split Green", G)
  6. cv.imshow("Split Red", R)
  7. # channel merging
  8. # zeros = np.zeros(shape=src.shape[:2], dtype=np.uint8)
  9. zeros = np.zeros(shape=B.shape, dtype=np.uint8)
  10. cv.imshow("Merge Blue", cv.merge([B, zeros, zeros]))
  11. cv.imshow("Merge Green", cv.merge([zeros, G, zeros]))
  12. cv.imshow("Merge Red", cv.merge([zeros, zeros, R]))
  13. # merge orignal image
  14. cv.imshow("orignal image", cv.merge([B, G, R]))
  15. cv.waitKey(0)
  16. cv.destroyAllWindows()
分离后的维数: (610, 570)

运行结果

split color

Merge color

Original image

B,G,R = cv.split(image)

  • 已知image.shape是610×570×3,如果只需要某个通道,那么最后的3就会变成1,所以B G R的维数应该是610×570;

  • 如果使用mv = cv.split(image),那么mvlist类型,有3个元素(np.array类型),每个元素是610×570维;

  • 如果单独显示通道的图像,发现三个通道的图像尽管不同,但都是灰色的,而不是期望中的红色等。以R为例,分离后图像会缺失G、B,但是使用imshow()方法后,三个通道都会变成R,即(R,R,R)当三个通道的值相等时,为灰度图

那我们如果要想显示红色,但是还得要用imshow()这个函数,就需要使用合并,把自动生成的(R,R,R),变成(R,0,0),也就是上面zeros那个矩阵的作用;

cv.merge([B, G, R])

需要注意:B,G,R的维数一定要相同;分离后各个通道的维数是610×570,为了确保维数相同,有这种写法:

  • zeros = np.zeros(shape=src.shape[:2], dtype=np.uint8)

  • 这里src.shape是610×570×3,也就是这个列表有三个元素,注意:src.shape[:2]是取不到最后一个元素的,只能取src.shape[0]、src.shape[1]这两个,src.shape[2]是取不到的;

  • zeros = np.zeros(shape=B.shape, dtype=np.uint8)这个写法是等价的,更简洁明了;

下面提供一种更简单直白的写法,思路是把无关通道的所有元素直接强行置0;比如:

  1. result_split = cv.split(src)
  2. # make G=R=0, only keep B;
  3. result_split[1][:,:] = 0
  4. result_split[2][:,:] = 0
  5. dst = cv.merge(result_split)
  6. cv.imshow("Merge Blue", dst)
  7. cv.waitKey(0)
  8. cv.destroyAllWindows()
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/79064
推荐阅读
相关标签
  

闽ICP备14008679号