网易首页 > 网易号 > 正文 申请入驻

SuperMemo实践闭环(3)-批量挖空制卡的操作

0
分享至

本文阐述了在不使用ImageOcclusionEditor的情况下,我们通过OpenCV实现批量图片遮挡的效果.

一. 运行环境-配置Python/脚本/终端环境

PyCharm / Python3.9 / Open-CV

PyCharm / Python3.9 的配置不再详细讲解,你可以参考我之前的专栏文章.

安装Open-CV的Python插件

解决找不到CV2 Module的问题:

.py文件运行时找不到,要注意在运行环境配置中添加变量

如果以上的方法还不能解决你的问题,请按这篇内容再配置一下:

用Pycharm运行后出现“No module named 'cv2'”错误的终极解决方案

blog.csdn.net/lhw19931201/article/details/86545964

终端单独运行找不到时,要确保你Python3.9的site-packages下存在cv2的模块

二. 脚本内容 - 如下脚本生成多个Occlusion图片至图床(使用了PicGo)并返回多个图片链接

OpenCV-Occlusion 脚本提供如下,具体操作步骤为:1.截图后对要制卡区绘制矩形遮挡并保存(注意保证矩形区透明度75%以上,而且能看到遮挡处的内容), 2.直接执行上面那条脚本:(如下代码区也有使用方法的说明) 3.如果遮挡生成的图片不对请酌情调整contourAreaValue参数

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import numpy as np
import cv2 as cv
import os
import sys
import requests
import json
from pprint import pprint
#################################
# 实现(opencv)批量生成挖空卡片,调用picGo上传并返回链接
# 作者:一只小胖子
# 版本:V0.1
# 知乎:https://www.zhihu.com/people/lxf-8868
# 使用方法:
# 1.使用snipaste截图,并用矩形工具描出实心遮挡区(注意:透明度为75%以上)
# 2.运行python3 occlusionCard.py "你的图片路径(包括后缀名)"
# 设置轮廓面积值,按效果自己调整,一般是1500-4000之间
contourAreaValue = 2500
#################################
# 设置putText函数字体
font = cv.FONT_HERSHEY_SIMPLEX
# 计算两边夹角额cos值
def angle_cos(p0, p1, p2):
d1, d2 = (p0 - p1).astype('float'), (p2 - p1).astype('float')
return abs(np.dot(d1, d2) / np.sqrt(np.dot(d1, d1) * np.dot(d2, d2)))
# 合并图片
def merge_img(image1, image2):
h1, w1, c1 = image1.shape
h2, w2, c2 = image2.shape
if c1 != c2:
print("channels NOT match, cannot merge")
return
else:
if w1 > w2:
tmp = np.zeros([h2, w1 - w2, c1])
image3 = np.hstack([image2, tmp])
image3 = np.vstack([image1, image3])
elif w1 == w2:
image3 = np.hstack([image1, image2])
else:
tmp = np.zeros([h1, w2 - w1, c2])
image3 = np.hstack([image1, tmp])
image3 = np.vstack([image3, image2])
return image3
# 查找矩形轮廓
def find_squares(filepath, flag):
img = cv.imread(filepath) # 读取图片对象
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (3, 3), 1) # 1
ret, th1 = cv.threshold(gray, 128, 255, 0) # cv.THRESH_OTSU) # 0,255,cv.THRESH_BINARY | cv.THRESH_OTSU 127, 255,0
# 开闭运算去除噪点
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (3, 3))
th1 = cv.morphologyEx(th1, cv.MORPH_OPEN, kernel)
th1 = cv.morphologyEx(th1, cv.MORPH_CLOSE, kernel)
binary = cv.Canny(th1, 50, 100)
contours, _hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE) # cv.RETR_EXTERNAL cv.RETR_TREE
print("轮廓数量:%d" % len(contours))
# 轮廓遍历
roi_list = []
contours_2 = []
for cnt in contours:
# cnt_len = cv.arcLength(cnt, True) # 计算轮廓周长
# cnt = cv.approxPolyDP(cnt, 0.02 * cnt_len, True) # 多边形逼近
# # 条件判断逼近边的数量是否为4,轮廓面积是否大于1000,检测轮廓是否为凸的
# if cv.contourArea(cnt) > 4000 and cv.isContourConvex(cnt):
if cv.contourArea(cnt) > contourAreaValue:
# 获取外接矩形的值
x, y, w, h = cv.boundingRect(cnt)
roi_list.append((x, y, w, h, cnt))
contours_2.append({"h": h, "cnt": cnt})
print("发现挖空[" + str(len(roi_list)) + "]处, contours数为[" + str(len(contours_2)) + "]")
squares_len = len(roi_list)
filenameAtr = filepath.rsplit("/")
for roi_idx in range(len(roi_list)):
index = 0
if flag == 1: # 正面 (将回答问题为红色遮挡,已回答的显示答案,其它为蓝色遮挡)
img = cv.imread(filepath)
for roi_list_ in roi_list:
(x, y, w, h, cnt_obj) = roi_list_
M = cv.moments(cnt_obj) # 计算轮廓的矩
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'] + h * 0.5 + 20) # 轮廓重心下移0.5倍高度
cv.putText(img, ("#%d" % index), (cx, cy), font, 0.8, (0, 128, 0), 2, cv.LINE_AA) # 抗锯齿
cv.drawContours(img, contours, 0, (255, 0, 255), 2)
if index < roi_idx:
index = index + 1
continue
elif index == roi_idx:
idx_red_col = (0, 0, 255) # 红色
else:
idx_red_col = (255, 0, 0) # 蓝色
cv.rectangle(img, (x, y), (x + w, y + h), idx_red_col, -1) # -1 2 -1为填充
index = index + 1
cv_filename = filenameAtr[0] + str(roi_idx) + "_A_" + filenameAtr[-1]
print(cv_filename)
# cv.imshow(cv_filename, img)
cv.imwrite(cv_filename, img)
elif flag == 0: # 反面
img2 = cv.imread(filepath)
for roi_list_ in roi_list:
(x, y, w, h, cnt_obj) = roi_list_
M = cv.moments(cnt_obj) # 计算轮廓的矩
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'] + h * 0.5 + 20) # 轮廓重心下移0.5倍高度
cv.putText(img2, ("#%d" % index), (cx, cy), font, 0.8, (0, 128, 0), 2, cv.LINE_AA) # 抗锯齿
cv.drawContours(img2, contours, 0, (255, 0, 255), 2)
if index <= roi_idx: # 已回答和正要回答的显示答案
index = index + 1
continue
else:
idx_red_col = (255, 0, 0) # 蓝色
cv.rectangle(img2, (x, y), (x + w, y + h), idx_red_col, -1) # -1 2 -1为填充
index = index + 1
cv_filename = filenameAtr[0] + str(roi_idx) + "_B_" + filenameAtr[-1]
print(cv_filename)
# cv.imshow(cv_filename, img2)
cv.imwrite(cv_filename, img2)
# cnt_len = cv.arcLength(cnt, True) # 计算轮廓周长
# cnt = cv.approxPolyDP(cnt, 0.02 * cnt_len, True) # 多边形逼近
# # 条件判断逼近边的数量是否为4,轮廓面积是否大于1000,检测轮廓是否为凸的
# if len(cnt) == 4 and cv.contourArea(cnt) > 1000 and cv.isContourConvex(cnt):
# M = cv.moments(cnt) # 计算轮廓的矩
# cx = int(M['m10'] / M['m00'])
# cy = int(M['m01'] / M['m00']) # 轮廓重心
#
# cnt = cnt.reshape(-1, 2)
# max_cos = np.max([angle_cos(cnt[i], cnt[(i + 1) % 4], cnt[(i + 2) % 4]) for i in range(4)])
# # 只检测矩形(cos90° = 0)
# if max_cos < 0.1:
# # True
# # 检测四边形(不限定角度范围)
# # if True:
# # if True:
# index = index + 1
# cv.putText(img, ("#%d" % index), (cx, cy), font, 0.7, (255, 0, 255), 2)
# squares.append(cnt)
return squares_len
# 逻辑执行入口
def main(img_file_path):
file_dir_path = os.path.dirname(img_file_path) + "/"
file_img_name = os.path.basename(img_file_path)
file_upload_list = [] # 待上传的图片列表
print("1.开始生成正面图像")
squares_len = find_squares(img_file_path, 1)
print("2.开始生成反面图像")
squares_len = find_squares(img_file_path, 0)
print("3.开始合成生成的图象")
for file_obj_idx in range(squares_len):
# print("{}{}{}{}".format(file_dir_path, file_obj_idx, "_A_", file_img_name))
# print("{}{}{}{}".format(file_dir_path, file_obj_idx, "_B_", file_img_name))
view1 = cv.imread("{}{}{}{}".format(file_dir_path, file_obj_idx, "_A_", file_img_name))
view2 = cv.imread("{}{}{}{}".format(file_dir_path, file_obj_idx, "_B_", file_img_name))
# 迭加图片模式
# cv.addWeighted(view1, alpha, src2, beta, gamma, dst=None, dtype=None)
# alpha/beta 对应两张图片的透明度, 0是完全透明 1是完全不透明
# overlapping = cv.addWeighted(view1, 0.8, view2, 0.2, 0)
# 合并的文件名
file_out_name = "{}{}_QA_{}".format(file_dir_path, file_obj_idx, file_img_name)
print(file_out_name)
# 只上传合并后的QA图片
file_upload_list.append(file_out_name)
# 水平或垂直合并图片
view3 = merge_img(view1, view2)
# cv.imshow('view3', view3)
cv.imwrite(file_out_name, view3)
# # Exit if ESC pressed
# # cv.waitKey()
k = cv.waitKey(100) & 0xff # 100ms
if k == 27:
cv.destroyAllWindows()
# exit()
# 获取图片存储目录待上传图片
print('\r\n图片处理生成至: {} 结束!'.format(file_dir_path))
print("开始上传图片,请确保你已提前配置好picGo上传环境...")
# # 获取传入路径下的: 当前目录, 子目录列表, 文件列表
# for f_path, dir_names, f_names in os.walk(file_dir_path):
# # 正常的图片文件,关键字查询过滤文件名
# f_names = [f_name for f_name in f_names if not f_name.startswith(".") and f_name.__contains__(".jpg")
# and os.path.isfile(f_name) and str(f_name).__contains__("#")]
# # 得到全路径信息
# f_names = [os.path.join(f_path, f_name) for f_name in f_names]
# break # 只处理根目录文件
print("待处理上传图片列表: {}".format(file_upload_list))
url = "http://127.0.0.1:36677/upload"
payload = json.dumps({
"list": file_upload_list
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print("PicGo上传返回结果:")
print(response)
obj_json_list = json.loads(response.text)
pprint(obj_json_list)
# 获取图片的URL链接
if "result" in obj_json_list.keys():
url_for_sm18 = [] # 格式化成SuperMemo网页样式
for url_ in obj_json_list["result"]:
url_str = "{}
".format(file_img_name, url_)
url_for_sm18.append(url_str)
print("上传成功,返回SuperMemo样式:") # $fileName
print("\r\n".join(url_for_sm18))
else:
print("上传失败,请检查是否重复上传!")
# ------------开始调用方法-------------
# 通过终端传参调用
img_path = str(sys.argv[1])
print("开始处理传入的图片:{}".format(img_path))
main(img_file_path=img_path)
# pycharm直接运行
# if __name__ == '__main__':
# # print(__doc__)
# img_path = "/Users/Likey/PycharmProjects/pythonProject/pic/33.jpg"
# main(img_path)

如果你用的是代码,下面的第三步骤可以不用再做了,代码已经实现了这个功能,第三步骤适合不用代码,直接手工操作的场景,总体上会麻烦一点....,建议你直接用代码的方式更方便.

三. Occlusion图片批量上传服务器并返回链接(这一步可以用上面第二步的代码替换了....)

(软件自带了一个网页链接,但这里我们要另外配置一个自定义链接用于获取批量的图片网址.)

通过以上的脚本生成了多个挖空Occlusion图片后,我们按需选中多个图片拖至PicGo软件的主界面进行上传,上传完后通过自定义的网页形式,批量获取图片网页链接.

四. 按以上方式通过代码或者手工获取到多个链接后,我们就可以直接在SuperMemo中处理了.

一只小胖子:SuperMemo实践闭环(4)-交互式处理网页材料2 赞同 · 2 评论文章

本文结束....

我是一只热爱学习的小胖子,如果你也热爱学习,并且对SuperMemo感兴趣,欢迎转发和评论!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
台湾新冠重症及死亡病例大幅增加

台湾新冠重症及死亡病例大幅增加

界面新闻
2024-06-19 10:40:22
后续!复旦法学院学生打老师:老师住医院,学生被调查,评论炸锅

后续!复旦法学院学生打老师:老师住医院,学生被调查,评论炸锅

影像温度
2024-06-19 22:58:57
王健林王思聪再回创富榜前十,甩卖资产不减反增之谜?

王健林王思聪再回创富榜前十,甩卖资产不减反增之谜?

BT财经
2024-06-20 07:00:02
照片曝光!菲海军特战队员被“兔子”海警断掉手指,已被菲官方授勋

照片曝光!菲海军特战队员被“兔子”海警断掉手指,已被菲官方授勋

不掉线电波
2024-06-18 23:00:53
奇了怪了,一说到哈马斯快被铲除了,就有人急得跳脚

奇了怪了,一说到哈马斯快被铲除了,就有人急得跳脚

非虚构故事
2024-06-19 14:28:58
余琦被立案调查!老公身份被扒,狗受牵连,前同事曝光其真实人品

余琦被立案调查!老公身份被扒,狗受牵连,前同事曝光其真实人品

六毛朵朵
2024-06-19 12:51:46
“我仅有这一辆车,你拿去我骑什么”,天在哭泣

“我仅有这一辆车,你拿去我骑什么”,天在哭泣

陶舜财经
2024-06-19 12:43:57
菲律宾军方承认:武器被中国缴获!受伤水兵的手指,换来一项嘉奖

菲律宾军方承认:武器被中国缴获!受伤水兵的手指,换来一项嘉奖

影孖看世界
2024-06-20 00:25:03
重大失误!日本大型银行误判欧美降息时机 遭受史上罕见损失

重大失误!日本大型银行误判欧美降息时机 遭受史上罕见损失

财联社
2024-06-19 21:51:10
36岁上海男子自爆和20岁贵州女友结婚,7年前支教认识时还是初中生

36岁上海男子自爆和20岁贵州女友结婚,7年前支教认识时还是初中生

可达鸭面面观
2024-06-19 14:19:08
“拜登身体机能衰退”?美官方回应

“拜登身体机能衰退”?美官方回应

新京报
2024-06-19 08:40:36
陈晓陈妍希婚变内幕:女方卑微挽回,疑患抑郁症,做音疗画面曝光

陈晓陈妍希婚变内幕:女方卑微挽回,疑患抑郁症,做音疗画面曝光

古希腊掌管月桂的神
2024-06-19 19:24:48
不该上热搜的“警税合成作战中心”,折射出了什么情绪?

不该上热搜的“警税合成作战中心”,折射出了什么情绪?

圆方你怎么看啊
2024-06-19 17:05:36
关于复旦毕业典礼打人事件…

关于复旦毕业典礼打人事件…

影迷Dustin
2024-06-19 23:12:20
如果英伟达面对警税合成作战中心,黄仁勋能干啥?

如果英伟达面对警税合成作战中心,黄仁勋能干啥?

今纶财经
2024-06-19 18:39:42
多家银行公告:6月23日将暂停个人线上跨行转账等服务

多家银行公告:6月23日将暂停个人线上跨行转账等服务

法制社会报
2024-06-19 08:48:27
杭州保姆纵火案通灵记录:通灵人与被害人交流,得知朱小贞真实死因

杭州保姆纵火案通灵记录:通灵人与被害人交流,得知朱小贞真实死因

古今档案
2024-06-18 20:56:33
高盛:中国正在考虑进行全面的消费税改革

高盛:中国正在考虑进行全面的消费税改革

风向观察
2024-06-19 19:07:10
国家社科基金项目成果:男人阴茎越短,智商越高

国家社科基金项目成果:男人阴茎越短,智商越高

必记本
2024-06-19 01:09:57
乌军遭斩首士兵头颅被摆在装甲车顶,俄军又对库皮扬斯克发起进攻

乌军遭斩首士兵头颅被摆在装甲车顶,俄军又对库皮扬斯克发起进攻

史政先锋
2024-06-19 19:27:50
2024-06-20 09:42:44
来自知乎的一只小胖子
来自知乎的一只小胖子
高效学习、知识管理、时间管理
55文章数 36关注度
往期回顾 全部

科技要闻

美国AI圈震动! “OpenAI宫斗”核心人物苏茨克维官宣创业

头条要闻

美媒:真主党有十几万枚炮弹 或3天摧毁以基础设施

头条要闻

美媒:真主党有十几万枚炮弹 或3天摧毁以基础设施

体育要闻

绿军的真老大,开始备战下赛季了

娱乐要闻

黄一鸣“杀疯了” 直播间卖大葱养孩子

财经要闻

茅台大跌,谁的锅?

汽车要闻

双肾格栅变化大/内饰焕新 新一代宝马X3官图发布

态度原创

旅游
游戏
本地
亲子
军事航空

旅游要闻

遭遇极端高温天气导致希腊多名游客死亡

DLC体量Mod《辐射4:新墨西哥》主创离开被搁置

本地新闻

中式沙拉宇宙的天花板,它必须有姓名

亲子要闻

这是带着绝技来的呀!睡觉还在压腿的宝宝!

军事要闻

以色列涉嫌在加沙使用重型炸弹 或多次违反战争法

无障碍浏览 进入关怀版