• OpenCV-Python实战(1) —— 给图片添加图片水印【利用 OpenCV 像素的读写原理实现】


    1. 需求分析

    1. 使用 OpenCV 图像像素读写操作原理,也就是 image[row][col] 获取和设值;
    2. 给图片添加水印:对应添加水印的位置,设置为水印图片的像素;
    3. 水印下能看到原图,也就是说水印必须是透明图片;
    4. 同时将水印透明位置像素(0,0,0)改变为同位置的图片的像素。

    2. 直接将水印添加到图片

    2.1 代码逻辑分析
    1. 读取水印logo图片;
    2. 读取需要添加水印的图片;
    3. 获取水印的宽高; 注意:此处水印使用的三通道读取,因此获取水印属性时需要加通道值。
    4. 利用图像像素读取设值原理,直接修改对应像素为水印像素;
    5. 注意:此处默认直接从坐标(0,0)开始直接修改【需要添加水印的图片】,如果其他位置,需要获取【需要添加水印的图片】的宽高等属性
    6. 显示添加水印后的图像。
    2.2 代码实现
    import cv2 as cv
    
    def add_logo_to_img():
      # 水印logo图片
      logo = cv.imread('./images/opencv-logo-white.png')
      # 需要添加水印的图片
      img = cv.imread('./images/messi5.jpg')
      # 获取水印的宽高,注意此处水印使用的三通道读取,因此获取水印属性时需要加通道值
      h,w,c = logo.shape
      # 利用图像像素读取设值原理,直接修改对应像素为水印像素
      img[:h,:w] = logo
      # 显示添加水印后的图像
      cv.imshow('add_logo', img)
      cv.waitKey(0)
      cv.destroyAllWindows()
    
    if __name__ == "__main__":
      add_logo_to_img()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    2.3 实现结果

    2.4 注意
    1. 此处水印使用的三通道读取,因此获取水印属性时需要加通道值。
    2. 注意:此处默认直接从坐标(0,0)开始直接修改。
    3. 此处的水印图片是透明的水印图片,因此加上水印后会看到水印周边很多黑色。
    4. 水印图片的宽高比原图尺寸小。
    2.5 非透明水印添加代码
    import cv2 as cv
    
    def add_logo_to_img():
      # 水印logo图片
      logo = cv.imread('./images/butterfly-mall.jpg')
      # 需要添加水印的图片
      img = cv.imread('./images/messi5.jpg')
      # 获取水印的宽高,注意此处水印使用的三通道读取,因此获取水印属性时需要加通道值
      h,w,c = logo.shape
      # 利用图像像素读取设值原理,直接修改对应像素为水印像素
      img[:h,:w] = logo
      # 显示添加水印后的图像
      cv.imshow('add_logo', img)
      cv.waitKey(0)
      cv.destroyAllWindows()
    
    if __name__ == "__main__":
      add_logo_to_img()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    2.5 非透明水印添加结果

    3. 遍历像素添加水印

    3.1 代码逻辑分析
    1. 读取水印logo图片;
    2. 读取需要添加水印的图片;
    3. 获取水印的宽高; 注意:此处水印使用的三通道读取,因此获取水印属性时需要加通道值。
    4. 利用图像像素读取设值原理,直接修改对应像素为水印像素;
    5. 遍历 logo 的像素,发现像素值是黑色(0,0,0)就替换为对应的原图像素【反之就是logo像素不是黑色的位置直接赋值给原图】;
    6. 注意:此处默认直接从坐标(0,0)开始直接修改【需要添加水印的图片】,如果其他位置,需要获取【需要添加水印的图片】的宽高等属性
    7. 显示添加水印后的图像。
    3.2 代码实现
    def add_logo_to_img():
      # 水印logo图片
      logo = cv.imread('./images/opencv-logo-white.png')
      # 需要添加水印的图片
      img = cv.imread('./images/messi5.jpg')
      # 获取水印的宽高,注意此处水印使用的三通道读取,因此获取水印属性时需要加通道值
      h,w,c = logo.shape
      # 利用图像像素读取设值原理,直接修改对应像素为水印像素
      # 遍历 logo 的像素,发现像素值是黑色(0,0,0)就替换为对应的原图像素【反之就是logo像素不是黑色的位置直接赋值给原图】
      for row in range(h):
        for col in range(w):
          b,g,r = logo[row][col]
          if b != 0 or g != 0 or r != 0:
            img[row][col] = (b,g,r)
      
      # 显示添加水印后的图像
      cv.imshow('add_logo', img)
      cv.waitKey(0)
      cv.destroyAllWindows()
    
    if __name__ == "__main__":
      add_logo_to_img()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    3.3 实现结果

    4. 改变水印的位置【居中】

    4.1 代码逻辑分析
    1. 在原来的基础上【获取原图的宽高属性】;
    2. 计算水印居中时的其实坐标;
    3. 修改像素值时,加上起始坐标的值,才是改变对应原图的像素坐标。
    4.2 代码实现
    import cv2 as cv
    
    def add_logo_to_img():
      # 水印logo图片
      logo = cv.imread('./images/opencv-logo-white.png')
      # 需要添加水印的图片
      img = cv.imread('./images/messi5.jpg')
      # 获取水印的宽高,注意此处水印使用的三通道读取,因此获取水印属性时需要加通道值
      h,w,c = logo.shape
      # 获取原图的宽高属性
      mh,mw,mc = img.shape
      # 计算水印居中时的其实坐标
      y = int((mh - h) / 2)
      x = int((mw - w) / 2)
      # 利用图像像素读取设值原理,直接修改对应像素为水印像素
      # 遍历 logo 的像素,发现像素值是黑色(0,0,0)就替换为对应的原图像素【反之就是logo像素不是黑色的位置直接赋值给原图】
      for row in range(h):
        for col in range(w):
          b,g,r = logo[row][col]
          if b != 0 or g != 0 or r != 0:
            img[row + y][col + x] = (b,g,r)
      
      # 显示添加水印后的图像
      cv.imshow('add_logo', img)
      cv.waitKey(0)
      cv.destroyAllWindows()
    
    if __name__ == "__main__":
      add_logo_to_img()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    4.3 实现结果

    5. 使用整体法实现水印的位置的改变

    5.1 代码逻辑分析
    1. 在第四步的基础上添加【截取添加水印位置和水印等大的图像】;
    2. 此时截取图像和水印图像大小一致;
    3. 直接使用第二步的方法,直接修改这个大小一致的截取图像,此处的方便在于不用遍历的时候每次都需要计算修改的位置
    4. 将修改后的截取图像还原回原图像;
    5. 实现添加水印效果。
    5.2 实现代码
    import cv2 as cv
    
    def add_logo_to_img():
      # 水印logo图片
      logo = cv.imread('./images/opencv-logo-white.png')
      # 需要添加水印的图片
      img = cv.imread('./images/messi5.jpg')
      # 获取水印的宽高,注意此处水印使用的三通道读取,因此获取水印属性时需要加通道值
      h,w,c = logo.shape
      # 获取原图的宽高属性
      mh,mw,mc = img.shape
      # 计算水印居中时的其实坐标
      y = int((mh - h) / 2)
      x = int((mw - w) / 2)
      # 截取和水印大小等同的原图需要改变位置的图像
      change_img = img[y:y+h,x:x+w]
      # 显示添加水印位置的截取图像
      cv.imshow('change_img', change_img)
      # 修改截取图片
      # 利用图像像素读取设值原理,直接修改对应像素为水印像素
      # 遍历 logo 的像素,发现像素值是黑色(0,0,0)就替换为对应的原图像素【反之就是logo像素不是黑色的位置直接赋值给原图】
      for row in range(h):
        for col in range(w):
          b,g,r = logo[row][col]
          if b != 0 or g != 0 or r != 0:
            change_img[row][col] = (b,g,r)
      # 显示截取图像添加水印后的效果
      cv.imshow('change_img_add_logo', change_img)
      # 将截取的图片还原到截取位置
      img[y:y+h,x:x+w] = change_img
      # 显示添加水印后的图像
      cv.imshow('add_logo', img)
      cv.waitKey(0)
      cv.destroyAllWindows()
    
    if __name__ == "__main__":
      add_logo_to_img()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    5.3 实现结果

    6. 总结

    1. 本篇文章是学习【图像像素读写操作】的实战实现;
    2. 文章还差水印文字的实现,水印图片大小的改变实现,在后续文章中学到了依旧会使用到开发实例中;
    3. 注意本文章都没有考虑图片的超出限制,如果是需要logo的部分等操作,需要另行操作;
    4. 注意本文章没有使用cv的其他二值处理等函数处理水印,所以水印最好是透明背景的图片,或者是纯色背景,方便获取背景的像素值。
  • 相关阅读:
    【JavaEE】_ajax构造HTTP请求
    Java类和对象
    PCB线路板蛇形布线要注意哪些问题?
    Haproxy搭建Web群集
    CGAL 入门基础
    数据分析相关暂存
    WordPress主题WoodMart v7.3.2 WooCommerce主题和谐汉化版下载
    安装rockylinux 9.2 版本虚拟机
    35.Python面向对象(八)【元类:type()、__metaclass__属性、实现简易ORM框架】
    202205(第13届)蓝桥杯Scratch图形化编程青少组(国赛_中级)真题
  • 原文地址:https://blog.csdn.net/m0_38082783/article/details/127445270