您現在的位置是:首頁 > 垂釣

SuperMemo實踐閉環(3)-批次挖空制卡的操作

  • 由 來自知乎的一隻小胖子 發表于 垂釣
  • 2022-08-02
簡介8, (0, 128, 0), 2, cv

怎麼新增制卡

本文闡述了在不使用ImageOcclusionEditor的情況下,我們透過OpenCV實現批次圖片遮擋的效果。

SuperMemo實踐閉環(3)-批次挖空制卡的操作

Occlusion指令碼執行後的效果如圖所示

一. 執行環境-配置Python/指令碼/終端環境

PyCharm / Python3。9 / Open-CV

PyCharm / Python3。9 的配置不再詳細講解,你可以參考我之前的專欄文章。

SuperMemo實踐閉環(3)-批次挖空制卡的操作

PyCharm中使用Python3。9編譯器

安裝Open-CV的Python外掛

pip3 install opencv-python

解決找不到CV2 Module的問題:

。py檔案執行時找不到,要注意在執行環境配置中新增變數

SuperMemo實踐閉環(3)-批次挖空制卡的操作

解決執行時找不到CV2模組的問題

如果以上的方法還不能解決你的問題,請按這篇內容再配置一下:

用Pycharm執行後出現“No module named ‘cv2’”錯誤的終極解決方案

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

SuperMemo實踐閉環(3)-批次挖空制卡的操作

終端單獨執行找不到時,要

確保你Python3.9的site-packages下存在cv2的模組

SuperMemo實踐閉環(3)-批次挖空制卡的操作

終端找不到CV2模組要確保。so存在

Likey@Laptop pythonProject % python3 。/occlusionCard。py “你的圖片路徑”

SuperMemo實踐閉環(3)-批次挖空制卡的操作

SuperMemo實踐閉環(3)-批次挖空制卡的操作

指令碼生成的最終SM樣式網頁

二. 指令碼內容 - 如下指令碼生成多個Occlusion圖片至圖床(使用了PicGo)並返回多個圖片連結

OpenCV-Occlusion 指令碼提供如下,具體操作步驟為:

1.截圖後對要制卡區繪製矩形遮擋並儲存(注意保證矩形區透明度75%以上,而且能看到遮擋處的內容), 2.直接執行上面那條指令碼:

如下程式碼區也有使用方法的說明) 3.如果遮擋生成的圖片不對請酌情調整contourAreaValue引數

#!/usr/bin/python3# -*- coding: utf-8 -*-import numpy as npimport cv2 as cvimport osimport sysimport requestsimport jsonfrom 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(‘圖片處理生成至: {} 結束!’。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(“”。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圖片批次上傳伺服器並返回連結(這一步可以用上面第二步的程式碼替換了....)

軟體自帶了一個網頁連結,但這裡我們要另外配置一個自定義連結用於獲取批次的圖片網址.)

SuperMemo實踐閉環(3)-批次挖空制卡的操作

先自定義返回圖片的連結格式

透過以上的指令碼生成了多個挖空Occlusion圖片後,我們

按需選中多個圖片拖至PicGo軟體的主介面進行上傳

上傳完後透過自定義的網頁形式,批次獲取圖片網頁連結.

SuperMemo實踐閉環(3)-批次挖空制卡的操作

主介面批次上傳多圖至服務端

SuperMemo實踐閉環(3)-批次挖空制卡的操作

獲取批次多圖的自定義格式連結

# 多圖的自定義返回連結QA_2_444  


QA_1_444  
QA_6_444  
QA_7_444  
20210228124446  

四. 按以上方式透過程式碼或者手工獲取到多個連結後,我們就可以直接在SuperMemo中處理了.

SuperMemo實踐閉環(3)-批次挖空制卡的操作

匯入批次圖片連結並分割為子問答

SuperMemo實踐閉環(3)-批次挖空制卡的操作

批次轉換子問答及新增模版

SuperMemo實踐閉環(3)-批次挖空制卡的操作

多圖片連結制卡的最終效果

一隻小胖子:SuperMemo實踐閉環(4)-互動式處理網頁材料

2 贊同 · 2 評論

文章

SuperMemo實踐閉環(3)-批次挖空制卡的操作

本文結束....

我是一隻熱愛學習的小胖子,如果你也熱愛學習,並且對SuperMemo感興趣,歡迎轉發和評論!

Top