python实现签章抠图,背景透明。签字、印章抠图,便于线上使用

您所在的位置:网站首页 如何用画图扣公章 python实现签章抠图,背景透明。签字、印章抠图,便于线上使用

python实现签章抠图,背景透明。签字、印章抠图,便于线上使用

2024-07-12 15:48| 来源: 网络整理| 查看: 265

线上审批等场景经常会用到手写签名、公司鲜章等,这篇文章介绍的就是如何定位抠图A4纸上的签名和鲜章的,并且可以批量处理。

主要使用opencv进行图像处理,把图像中的文字和印章轮廓处理出来,然后再进行定位裁剪,最后背景透明化。

先放效果图 扫描原图

抠出的印章在表格上的效果

自动定位图片上的所有签字并抠图

抠出签名的效果

代码  印章部分 def yz(imgname): original_image = cv2.imread(imgname) image = original_image.copy() gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (3, 3), 0) canny = cv2.Canny(blurred, 120, 255, 1) # 找到图片中的轮廓 cnts = cv2.findContours(canny.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] # 按照面积将所有轮廓逆序排序 contours2 = sorted(cnts, key=lambda a: cv2.contourArea(a), reverse=True) ROI_number = 0 for c in contours2: area = cv2.contourArea(c) print(area) # 只抠面积大于1200的轮廓,一般印章的轮廓面积比较大,可根据实际情况调整 if area < 1200: break x, y, w, h = cv2.boundingRect(c) # 调整裁剪的位置,避免印章的边缘缺失 x -= 20 y -= 20 w += 40 h += 40 cv2.rectangle(image, (x, y), (x + w, y + h), (36, 255, 12), 1) ROI = original_image[y:y + h, x:x + w] # cv2.imshow("ROI", ROI) img_name = imgname[0: imgname.rindex(".")] + '_{}.png'.format(ROI_number) cv2.imwrite(img_name, ROI) pic = Image.open(img_name) # 转为RGBA模式 pic = pic.convert('RGBA') width, height = pic.size # 获取图片像素操作入口 array = pic.load() for i in range(width): for j in range(height): # 获得某个像素点,格式为(R, G, B, A)元组 pos = array[i, j] # RGB三者都大于240(很接近白色了) isEdit = (sum([1 for x in pos[0:3] if x > 240]) == 3) if isEdit: # 更改为透明 array[i, j] = (255, 255, 255, 0) # 保存图片 pic.save(img_name) ROI_number += 1  签字部分,原理和印章一样,只不过签字有的不是连着的,所以要合并相邻的轮廓,保证扣出来的是完整的签名 def opcvimg(cur_path): # 加载图像、灰度、高斯模糊、自适应阈值 image = cv2.imread(cur_path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (9, 9), 0) thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 30) # 扩大以合并相邻的文本轮廓 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10)) dilate = cv2.dilate(thresh, kernel, iterations=6) # 查找轮廓、突出显示文本区域并提取 ROI cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] ROI_number = 0 for c in cnts: area = cv2.contourArea(c) if area > 100: x, y, w, h = cv2.boundingRect(c) x -= 20 y -= 20 w += 40 h += 40 # cv2.rectangle(image, (x, y), (x + w, y + h), (36, 255, 12), 2) ROI = image[y:y + h, x:x + w] img_name = cur_path[0: cur_path.rindex(".")] + '_{}.png'.format(ROI_number) cv2.imwrite(img_name, ROI) ROI_number += 1 cv2.imwrite(img_name, ROI) pic = Image.open(img_name) pic = pic.convert('RGBA') width, height = pic.size array = pic.load() for i in range(width): for j in range(height): pos = array[i, j] isEdit = (sum([1 for x in pos[0:3] if x > 240]) == 3) if isEdit: array[i, j] = (255, 255, 255, 0) pic.save(img_name) 完整代码,引入flask-restful,api使得程序可以组件化单独部署,提供抠图能力 #!/usr/bin/python # encoding: utf-8 import cv2 import PIL.Image as Image import os from flask import Flask from flask_restful import Api, Resource, request app = Flask(__name__) api = Api(app) class DetectSign(Resource): """ 提取签名和印章 """ def get(self): try: path = request.args['path'] type = request.args['type'] show_files(path, type) return {"msg": "成功", "code": 200} except Exception as e: print(e) return {"msg": "失败", "code": 500} def show_files(path, type): if path is None: return if ".jpg" in path or ".png" in path or ".gif" in path: try: if type == '0': yz(path) else: opcvimg(path) except Exception as e: print(e) else: # 首先遍历当前目录所有文件及文件夹 file_list = os.listdir(path) # 准备循环判断每个元素是否是文件夹还是文件,是文件的话,把名称传入list,是文件夹的话,递归 for file in file_list: # 利用os.path.join()方法取得路径全名,并存入cur_path变量,否则每次只能遍历一层目录 cur_path = os.path.join(path, file) # 判断是否是文件夹 if os.path.isdir(cur_path): show_files(cur_path) else: print(cur_path) if ".jpg" in cur_path or ".png" in cur_path or ".gif" in cur_path: try: if type == '0': yz(cur_path) else: opcvimg(cur_path) except Exception as e: print(e) def opcvimg(cur_path): image = cv2.imread(cur_path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (9, 9), 0) thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 30) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10)) dilate = cv2.dilate(thresh, kernel, iterations=6) cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] ROI_number = 0 for c in cnts: area = cv2.contourArea(c) if area > 100: x, y, w, h = cv2.boundingRect(c) x -= 20 y -= 20 w += 40 h += 40 # cv2.rectangle(image, (x, y), (x + w, y + h), (36, 255, 12), 2) ROI = image[y:y + h, x:x + w] img_name = cur_path[0: cur_path.rindex(".")] + '_{}.png'.format(ROI_number) cv2.imwrite(img_name, ROI) ROI_number += 1 cv2.imwrite(img_name, ROI) pic = Image.open(img_name) pic = pic.convert('RGBA') width, height = pic.size array = pic.load() for i in range(width): for j in range(height): pos = array[i, j isEdit = (sum([1 for x in pos[0:3] if x > 240]) == 3) if isEdit: array[i, j] = (255, 255, 255, 0) pic.save(img_name) def yz(imgname): original_image = cv2.imread(imgname) image = original_image.copy() gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (3, 3), 0) canny = cv2.Canny(blurred, 120, 255, 1) cnts = cv2.findContours(canny.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] contours2 = sorted(cnts, key=lambda a: cv2.contourArea(a), reverse=True) ROI_number = 0 for c in contours2: area = cv2.contourArea(c) print('图像面积:', area) if area < 1200: break x, y, w, h = cv2.boundingRect(c) x -= 20 y -= 20 w += 40 h += 40 cv2.rectangle(image, (x, y), (x + w, y + h), (36, 255, 12), 1) ROI = original_image[y:y + h, x:x + w] # cv2.imshow("ROI", ROI) img_name = imgname[0: imgname.rindex(".")] + '_{}.png'.format(ROI_number) cv2.imwrite(img_name, ROI) pic = Image.open(img_name) pic = pic.convert('RGBA') width, height = pic.size array = pic.load() for i in range(width): for j in range(height): pos = array[i, j] isEdit = (sum([1 for x in pos[0:3] if x > 240]) == 3) if isEdit: array[i, j] = (255, 255, 255, 0) pic.save(img_name) ROI_number += 1 # 设置路由 api.add_resource(DetectSign, '/x-api/v1/ai/detect/sign') if __name__ == '__main__': # 将host设置为0.0.0.0,则外网用户也可以访问到这个服务 app.run('0.0.0.0', 8386, debug=True) 有编译打包好的 exe程序文件可以下载。

https://download.csdn.net/download/puremilkll/21739417



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3