一、前言
上次的文章告诉大家制作自己独有的二维码这个码,妙不可言!,今天分享一下如何像我一样制作一个海报,替换海报上的二维码。
地址:https://blog.csdn.net/qq_36441393/article/details/111411608
当时这个想法是这样来的:业主群里每天早上都有物业人员分享一副海报,我觉得海报挺让人赏心悦目的,我如果分享到朋友圈也挺不错,但是海报上面有个物业公司的二维码,我想何不换成我的二维码试试。(我知道美图秀秀等软件可以做到,但是技术人就是不一样,非要折腾!)
来自物业的海报
二、方法
我们技术人换二维码怎么换呢?
我们理一下思路,如果我们替换这个二维码,用手机P图软件该是什么思路,我们的步骤应该是这样:
1、找到原图二维码的位置。
2、缩放将要覆盖的二维码大小。
3、粘贴到原图二维码位置。
好的,技术人已经知道该怎么做了。
首先找二维码,利用python的opencv库来实现即可。这个二维码出现的位置很突出,在右下角,那我们完全可以通过找图中的轮廓,然后得到最右下角的轮廓位置即可,分别得到二维码的起始坐标点和尺寸宽高。代码参考如下。
import cv2
#==========获得二维码起始坐标位置和尺寸大小==
def find_code(pic_file):
# print("请输入解码图片完整名称:")
# code_name = input('>>:').strip()
# print("正在识别:")
image = cv2.imread(pic_file)
# image = cv2.imread(code_name)
# 灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 使用opencv自带的Sobel算子进行过滤
gradX = cv2.Sobel(gray, ddepth=cv2.cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradY = cv2.Sobel(gray, ddepth=cv2.cv2.CV_32F, dx=0, dy=1, ksize=-1)
# 将过滤得到的X方向像素值减去Y方向的像素值
gradient = cv2.subtract(gradX, gradY)
# 先缩放元素再取绝对值,最后转换格式为8bit型
gradient = cv2.convertScaleAbs(gradient)
# 均值滤波取二值化
blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
# 腐蚀和膨胀的函数
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, None, iterations=4)
closed = cv2.dilate(closed, None, iterations=4)
cv2.imwrite('./pic/closed.jpg', closed)
# 找到边界findContours函数
(_, cnts, _) = cv2.findContours(closed.copy(),
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(cnts,type(cnts))
a =cnts
print(a,type(a),len(a))
# 计算出包围目标的最小矩形区域
c = sorted(cnts, key=cv2.contourArea, reverse=False)[0]
tmp =0
max =0
len(a)
for i in range(len(a)):
xy =a[i][-1][0][0] + a[i][-1][0][1]
if xy >max:
max =xy
tmp= i
# print(a[i][0][0],a[i][0][1])
# print(tmp)
# print(a[tmp])
rect = cv2.minAreaRect(c)
rect1 = cv2.minAreaRect(a[tmp])
# print(rect,rect1)
box = np.int0(cv2.boxPoints(rect1))
print(box)
#======显示=======
# windowname ="ScanQRcodeTest"
# cv2.namedWindow(windowname, cv2.WINDOW_NORMAL)
# cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
# cv2.imshow(windowname, image)
# cv2.waitKey(0)
#===============
#=========保存证据=======
# 绘制轮廓
cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
cv2.imwrite('./pic/findresult.jpg',image)
# ====获得二维码起始坐标位置和尺寸大小
x0,y0 = box[1][0],box[1][1]
x3,y3 =box[3][0],box[3][1]
height = y3-y0
width = x3 -x0
return x0,y0 ,height,width
通过以上代码,我们能找到二维码框。下图绿色框出。
预处理后找到二维码位置
好了,找到这个二维码位置,然后就该上我们自己的二维码了,之前有介绍过自己二维码的生成,这个码,妙不可言!。但是用之前需要把我们自己生成的二维码尺寸进行一个缩放,这样才能比较合适的覆盖上去。那尺寸依据原图上的二维码尺寸进行缩放。缩放后利用python的Image库的paste在原位置上进行覆盖。代码参考如下。
import qrcode
my_str ='https://mp.weixin.qq.com/s/jbEeVf8i9cm7yKaQP9SVoQ'
my_qrcode_filename ='./pic/simpleqrcode.jpg'
img = qrcode.make(my_str)
img.save(my_qrcode_filename)
#========找位置==========
pic_file ='./pic/pic1221.jpg'
x0,y0 ,height,width=find_code(pic_file)
#========对粘贴的二维码进行尺寸调整==========
img = cv2.imread(my_qrcode_filename)
img_copy = img.copy()
img_copy = cv2.resize(img_copy,(width+10,height+10))
cv2.imwrite('./pic/yudaresize.jpg',img_copy)
#=========粘贴新二维码===========
from PIL import Image
import matplotlib.pyplot as plt
img= Image.open(pic_file)
img2=Image.open(r'./pic/yudaresize.jpg')
img.paste(img2,(x0-5,y0-5,x0+width+5,y0+height+5))
# plt.imshow(img)
# plt.show()
img.save("./pic/newpic.jpg")
三、总结
这样基本就完成了所有任务,还算比较简单吧。
其中最为关键的是二维码的位置提取,目前只是基于这个物业公司的海报进行的匹配,若是复杂背景或可能需要在代码上做参数调整或逻辑上的调整。
当然做的更好的算法是用深度学习目标检测,这样需要我们进行一些标注,训练出一个合适的模型,有时间的朋友可以尝试。