经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
python将红底证件照转成蓝底的实现方法
来源:jb51  时间:2022/8/31 17:27:00  对本文有异议

前言

emmm…9月1日开学季,手头只有红底证件照,但是学院要求要蓝底,这可咋办呢。懒得下ps了。自己撸起来吧。

方法一: lableme

lableme标注完后。得到一个json文件,然后将这种json文件转成掩码图.

  1. # 代码来自 https://blog.csdn.net/hello_dear_you/article/details/120130155
  2. import json
  3. import numpy as np
  4. import cv2
  5. # read json file
  6. with open("origin_json/mypic.json", "r") as f:
  7. data = f.read()
  8. # convert str to json objs
  9. data = json.loads(data)
  10. # get the points
  11. points = data["shapes"][0]["points"]
  12. points = np.array(points, dtype=np.int32) # tips: points location must be int32
  13. # read image to get shape
  14. image = cv2.imread("origin_png/person.jpg")
  15. # create a blank image
  16. mask = np.zeros_like(image, dtype=np.uint8)
  17. # fill the contour with 255
  18. cv2.fillPoly(mask, [points], (255, 255, 255))
  19. # save the mask
  20. cv2.imwrite("mask/person_mask.png", mask)

大概是这样:

然后利用这个mask生成图片

  1. # 参考自: https://www.jianshu.com/p/1961aa0c02ee
  2. import cv2
  3. import numpy as np
  4. origin_png = 'origin_png/person.jpg'
  5. # maskPath = 'mask/person_mask.png'
  6. maskPath = 'mask/bmv2.png'
  7. result_png = 'result_png/result_png.png'
  8. maskImg = cv2.imread(maskPath)
  9. img = cv2.imread(origin_png)
  10. assert maskImg.shape == img.shape, 'maskImg.shape != origin_png.shape'
  11.  
  12. h, w = img.shape[0], img.shape[1]
  13. print('图片宽度: {}, 高度: {}'.format(h, w))
  14.  
  15. rgb = (19,122,171)
  16. bgr = (rgb[2], rgb[1], rgb[0])
  17. # (B, G, R)
  18. for i in range(h):
  19. for j in range(w):
  20. if (maskImg[i, j] == 0).all():
  21. img[i, j] = bgr
  22. cv2.imwrite(result_png, img)
  23. print('图片写入 {} 成功'.format(result_png))

由于人长得一般,就不放图了…

缺点:
lableme标注时挺费力,并且难以避免人与背景边缘会有残留红色像素的情况。

方法二: 阈值

该方法通过比较像素的RGB与背景的RGB来区分是否为图像背景。

Opencv

  1. import cv2
  2. import numpy as np
  3. def mean_square_loss(a_np, b_np):
  4. sl = np.square(a_np - b_np)
  5. return np.mean(sl)
  6. def change_red2blue(origin_png, result_png):
  7. img = cv2.imread(origin_png)
  8. h, w = img.shape[0], img.shape[1]
  9. print('图片宽度: {}, 高度: {}'.format(h, w))
  10. origin_rgb = (168,36,32) # 可以用浏览器啥的控制台工具提取出背景的rgb值
  11. origin_bgr = (origin_rgb[2], origin_rgb[1], origin_rgb[0])
  12. target_rgb = (19,122,171) # 蓝底RBG
  13. target_bgr = (target_rgb[2], target_rgb[1], target_rgb[0])
  14. for i in range(h):
  15. for j in range(w):
  16. # (B, G, R)
  17. if mean_square_loss(img[i, j], origin_bgr) < 50:
  18. img[i, j] = target_bgr
  19. cv2.imwrite(result_png, img)
  20. print('图片写入 {} 成功'.format(result_png))
  21. if __name__ == '__main__':
  22. # origin_png = 'result_png/result_png.png'
  23. origin_png = 'origin_png/person.jpg'
  24. result_png = 'result_png/result_refine.png'
  25. change_red2blue(origin_png, result_png)

结果人与背景边缘仍会存在红色像素残留

PIL

  1. from torchvision.transforms.functional import to_tensor, to_pil_image
  2. from PIL import Image
  3. import torch
  4. import time
  5. def mean_square_loss(a_ts, b_ts):
  6. # print(a_ts.shape)
  7. # print(b_ts)
  8. sl = (a_ts - b_ts) ** 2
  9. return sl.sum()
  10. def change_red2blue(origin_png, result_png):
  11. src = Image.open(origin_png)
  12. src = to_tensor(src)
  13. # print(src.shape) # torch.Size([3, 800, 600])
  14. # channel: (R, G, B) / 255
  15. h, w = src.shape[1], src.shape[2]
  16.  
  17. pha = torch.ones(h, w, 3)
  18.  
  19. bg = torch.tensor([168,36,32]) / 255
  20. target_bg = torch.tensor([19,122,171]) / 255
  21.  
  22. # C, H, W -> H, W, C
  23. src = src.permute(1, 2, 0)
  24. for i in range(h):
  25. for j in range(w):
  26. if mean_square_loss(src[i][j], bg) < 0.025: # 0.025是阈值,超参数
  27. pha[i][j] = torch.tensor([0.0, 0.0, 0.0])
  28.  
  29. # H, W, C -> C, H, W
  30. src = src.permute(2, 0, 1)
  31. pha = pha.permute(2, 0, 1)
  32. com = pha * src + (1 - pha) * target_bg.view(3, 1, 1)
  33. to_pil_image(com).save(result_png)
  34. if __name__ == '__main__':
  35. origin_png = 'origin_png/person.jpg'
  36. result_png = 'result_png/com.png'
  37. start_time = time.time()
  38. change_red2blue(origin_png, result_png)
  39. spend_time = round(time.time() - start_time, 2)
  40. print('生成成功,共花了 {} 秒'.format(spend_time))

该方法质量较好,但一张图片大概需要12秒。

方法三: Background MattingV2

Real-Time High-Resolution Background Matting
CVPR 2021 oral

论文:https://arxiv.org/abs/2012.07810
代码:https://github.com/PeterL1n/BackgroundMattingV2

github的readme.md有inference的colab链接,可以用那个跑

由于这篇论文是需要输入一张图片(例如有人存在的草地上)和背景图片的(如果草地啥的), 然后模型会把人抠出来。

于是这里我需要生成一个背景图片。
首先我先借助firefox的颜色拾取器(或者微信截图,或者一些在线工具,例如菜鸟工具),得到十六进制,再用在线转换工具转成rgb。

然后生成一个背景图片。

  1. import cv2
  2. import numpy as np
  3. image = cv2.imread("origin_png/person.jpg")
  4. origin_rgb = (168,36,32) # 可以用浏览器啥的控制台工具提取出背景的rgb值
  5. origin_bgr = (origin_rgb[2], origin_rgb[1], origin_rgb[0])
  6. image[:, :] = origin_bgr
  7. cv2.imwrite("mask/bg.png", image)

需要上传人的照片和背景照片, 如果名字和路径不一样则需要修改一下代码

  1. src = Image.open('src.png')
  2. bgr = Image.open('bgr.png')

另外原论文是边绿底,要变蓝底,白底,红底则可以修改RGB值,举个例子,原来是这样的(绿底, RGB120, 255, 155)

  1. com = pha * fgr + (1 - pha) * torch.tensor([120/255, 255/255, 155/255], device='cuda').view(1, 3, 1, 1)

那么加入我要换白底(255, 255, 255),就是

  1. com = pha * fgr + (1 - pha) * torch.tensor([255/255, 255/255, 255/255], device='cuda').view(1, 3, 1, 1)

假如像我换蓝底(19,122,171)具体深浅可以调节一下RGB,就是

  1. com = pha * fgr + (1 - pha) * torch.tensor([19/255, 122/255, 171/255], device='cuda').view(1, 3, 1, 1)

总结: 其实这种方法从 任何颜色的照片 都可以 换成任何颜色的底。只要换下RGB.

然后就输出图片了。可以看到效果相当好。不愧是oral。

原论文可以实现发丝级效果

报错解决方案
can’t divided by 4 / can’t divided by 16
由于该骨干模型可能进行4倍或16倍下采样,因此如果您的证件照不是该倍数的话,有两种选择方案。一种是padding, 填充后再送入模型,然后出结果后再用clip函数裁剪。另一种方式是resize, 给resize到规定倍数的宽和高。
这两种方案需要的代码都可以从这篇博文找到: python图像填充与裁剪/resize

到此这篇关于python将红底证件照转成蓝底的文章就介绍到这了,更多相关python证件照转换内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号