目录
前言方法一: lableme方法二: 阈值OpencvPIL方法三: Background MattingV2前言
emmm…9月1日开学季,手头只有红底证件照,但是学院要求要蓝底,这可咋办呢。懒得下ps了。自己撸起来吧。
方法一: lableme
lableme标注完后。得到一个json文件,然后将这种json文件转成掩码图.
【资料图】
# 代码来自 https://blog.csdn.net/hello_dear_you/article/details/120130155 import json import numpy as np import cv2 # read json file with open("origin_json/mypic.json", "r") as f: data = f.read() # convert str to json objs data = json.loads(data) # get the points points = data["shapes"][0]["points"] points = np.array(points, dtype=np.int32) # tips: points location must be int32 # read image to get shape image = cv2.imread("origin_png/person.jpg") # create a blank image mask = np.zeros_like(image, dtype=np.uint8) # fill the contour with 255 cv2.fillPoly(mask, [points], (255, 255, 255)) # save the mask cv2.imwrite("mask/person_mask.png", mask)
大概是这样:
然后利用这个mask生成图片
# 参考自: https://www.jianshu.com/p/1961aa0c02ee import cv2 import numpy as np origin_png = "origin_png/person.jpg" # maskPath = "mask/person_mask.png" maskPath = "mask/bmv2.png" result_png = "result_png/result_png.png" maskImg = cv2.imread(maskPath) img = cv2.imread(origin_png) assert maskImg.shape == img.shape, "maskImg.shape != origin_png.shape" h, w = img.shape[0], img.shape[1] print("图片宽度: {}, 高度: {}".format(h, w)) rgb = (19,122,171) bgr = (rgb[2], rgb[1], rgb[0]) # (B, G, R) for i in range(h): for j in range(w): if (maskImg[i, j] == 0).all(): img[i, j] = bgr cv2.imwrite(result_png, img) print("图片写入 {} 成功".format(result_png))
由于人长得一般,就不放图了…
缺点:
lableme标注时挺费力,并且难以避免人与背景边缘会有残留红色像素的情况。
方法二: 阈值
该方法通过比较像素的RGB与背景的RGB来区分是否为图像背景。
Opencv
import cv2 import numpy as np def mean_square_loss(a_np, b_np): sl = np.square(a_np - b_np) return np.mean(sl) def change_red2blue(origin_png, result_png): img = cv2.imread(origin_png) h, w = img.shape[0], img.shape[1] print("图片宽度: {}, 高度: {}".format(h, w)) origin_rgb = (168,36,32) # 可以用浏览器啥的控制台工具提取出背景的rgb值 origin_bgr = (origin_rgb[2], origin_rgb[1], origin_rgb[0]) target_rgb = (19,122,171) # 蓝底RBG target_bgr = (target_rgb[2], target_rgb[1], target_rgb[0]) for i in range(h): for j in range(w): # (B, G, R) if mean_square_loss(img[i, j], origin_bgr) < 50: img[i, j] = target_bgr cv2.imwrite(result_png, img) print("图片写入 {} 成功".format(result_png)) if __name__ == "__main__": # origin_png = "result_png/result_png.png" origin_png = "origin_png/person.jpg" result_png = "result_png/result_refine.png" change_red2blue(origin_png, result_png)
结果人与背景边缘仍会存在红色像素残留
PIL
from torchvision.transforms.functional import to_tensor, to_pil_image from PIL import Image import torch import time def mean_square_loss(a_ts, b_ts): # print(a_ts.shape) # print(b_ts) sl = (a_ts - b_ts) ** 2 return sl.sum() def change_red2blue(origin_png, result_png): src = Image.open(origin_png) src = to_tensor(src) # print(src.shape) # torch.Size([3, 800, 600]) # channel: (R, G, B) / 255 h, w = src.shape[1], src.shape[2] pha = torch.ones(h, w, 3) bg = torch.tensor([168,36,32]) / 255 target_bg = torch.tensor([19,122,171]) / 255 # C, H, W -> H, W, C src = src.permute(1, 2, 0) for i in range(h): for j in range(w): if mean_square_loss(src[i][j], bg) < 0.025: # 0.025是阈值,超参数 pha[i][j] = torch.tensor([0.0, 0.0, 0.0]) # H, W, C -> C, H, W src = src.permute(2, 0, 1) pha = pha.permute(2, 0, 1) com = pha * src + (1 - pha) * target_bg.view(3, 1, 1) to_pil_image(com).save(result_png) if __name__ == "__main__": origin_png = "origin_png/person.jpg" result_png = "result_png/com.png" start_time = time.time() change_red2blue(origin_png, result_png) spend_time = round(time.time() - start_time, 2) 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。
然后生成一个背景图片。
import cv2 import numpy as np image = cv2.imread("origin_png/person.jpg") origin_rgb = (168,36,32) # 可以用浏览器啥的控制台工具提取出背景的rgb值 origin_bgr = (origin_rgb[2], origin_rgb[1], origin_rgb[0]) image[:, :] = origin_bgr cv2.imwrite("mask/bg.png", image)
需要上传人的照片和背景照片, 如果名字和路径不一样则需要修改一下代码
src = Image.open("src.png") bgr = Image.open("bgr.png")
另外原论文是边绿底,要变蓝底,白底,红底则可以修改RGB值,举个例子,原来是这样的(绿底, RGB120, 255, 155)
com = pha * fgr + (1 - pha) * torch.tensor([120/255, 255/255, 155/255], device="cuda").view(1, 3, 1, 1)
那么加入我要换白底(255, 255, 255),就是
com = pha * fgr + (1 - pha) * torch.tensor([255/255, 255/255, 255/255], device="cuda").view(1, 3, 1, 1)
假如像我换蓝底(19,122,171)具体深浅可以调节一下RGB,就是
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证件照转换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
X 关闭
X 关闭
- 1联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 2亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 3现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 4如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 5AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 6转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 7充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 8好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 9名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?
- 10亚马逊云科技成立量子网络中心致力解决量子计算领域的挑战