[PYTHON] G-Test misst das OCR-Faltungsberechnungswerkzeug

Überblick

Dies ist der erste Beitrag. Ich fragte mich, ob ich die Faltungsberechnung des Gerüchts irgendwie automatisieren könnte, als es mit dem G-Test herauskam. Ich denke nicht, dass dies eine Berechnung ist, dass Menschen ihr Bestes geben.

Im Inneren --PySimpleGUI (Ich wollte unbedingt Kivy verwenden) --Spezifikation durch Ziehen der Maus mit OpenCV

Der Code ist auch unten. https://github.com/poohsanforest/ConvCalcOCR

Erforderliche Module

Wie benutzt man

  1. Geben Sie den Namen des Fensters, das Sie lesen möchten, in das obere Feld ein und drücken Sie die Taste rechts, um den Bildschirm unten rechts anzuzeigen. Selbst wenn Sie den Tab-Namen in Chrome eingeben, wird ein schwarzer Bildschirm angezeigt. Es ist daher besser, den Tab-Namen in Firefox einzugeben. (Kein Zugriff ohne Chrome-Treiber möglich?)
  2. Wenn Sie die Filtertaste drücken, wird ein Popup angezeigt. Wählen Sie daher das Faltfilterteil so aus, dass das Gitter passt.
  3. Verwenden Sie die Zieltaste, um das Ziel auszuwählen, das Sie falten möchten.
  4. Wenn der in jedem Textfeld gelesene Wert falsch ist, korrigieren Sie ihn. (Als Prozentsatz falsch eingeschätzt)
  5. Drücken Sie die Berechnungstaste, um das Ergebnis der Faltungsberechnung anzuzeigen.

Testbild (in Firefox geöffnet)

Aussehensteil

Ich mache einen GUI-Teil mit PySimpleGUI. Die Funktionen redefine_rectangle und draw_shape können hilfreich sein, wenn Sie Koordinaten durch Ziehen der Maus abrufen.

import sys
import PySimpleGUI as sg
import numpy as np
import cv2
import win32gui
import win32ui
import win32con
import pyocr
import re
from PIL import Image
from scipy import signal


#Da ich win32api verwende, funktioniert es unter Unix nicht so wie es ist
class ConvCalc():
    def __init__(self, **kwargs):
        self.drawing = False
        self.flag_drawing = False
        self.flag_filter = True
        self.roi_filter = [[0, 0], [50, 50]]
        self.roi_target = [[0, 0], [50, 50]]
        self.roi_temp = [[0, 0], [50, 50]]
        self.image_filter = np.zeros((300, 300, 3), np.uint8)
        self.image_target = np.zeros((300, 300, 3), np.uint8)
        self.image_capture = np.zeros((300, 300, 3), np.uint8)
        self.image_copy = np.zeros((300, 300, 3), np.uint8)
        self.tool = None

    #Beginnen Sie mit der Auswahl des Rechtecks
    def redefine_rectangle(self, cols, rows, color):
        cv2.namedWindow("set ROI")
        cv2.setMouseCallback("set ROI", self.draw_shape)
        self.flag_drawing = True

        while 1:
            image_rect = rectangle_grid(self.image_copy.copy(),
                                    tuple(self.roi_filter[0] if self.flag_filter else self.roi_target[0]),
                                    tuple(self.roi_filter[1] if self.flag_filter else self.roi_target[1]),
                                    color,
                                    cols, rows,
                                    1)

            cv2.imshow("set ROI", image_rect)
            cv2.waitKey(1)

            #× Tastenerkennung
            ret = cv2.getWindowProperty('set ROI', cv2.WND_PROP_ASPECT_RATIO)
            
            #Ich frage mich, ob ich mit dem Schreiben fertig sein oder mit der Taste × brechen und die Taste nicht verarbeiten soll
            if not self.flag_drawing or ret == -1.0:
                #Geteilte Bilderstellung
                divided_image = divide_image(self.image_copy, self.roi_filter if self.flag_filter else self.roi_target, cols, rows, 0.08)
                score_list = []
                for c, divided in enumerate(divided_image):
                    txt = self.tool.image_to_string(
                        Image.fromarray(cv2.cvtColor(divided, cv2.COLOR_BGR2RGB)),
                        lang="eng",
                        # builder=pyocr.builders.TextBuilder(tesseract_layout=6),
                        builder=pyocr.tesseract.DigitBuilder(tesseract_layout=6),
                    )
                    score_list.append(float(fix_num(txt)))

                #Umformen auf die Dimension von Rowcol
                score_list_reshaped = fix_textbox(score_list, rows, cols)

                #Reflektieren Sie den erkannten Zahlenwert
                if self.flag_filter:
                    self.image_filter = image_rect
                    self.window['filterarray'].update(score_list_reshaped)
                else:
                    self.image_target = image_rect
                    self.window['targetarray'].update(score_list_reshaped)

                break
        
        #Zeichnen Sie den endgültigen Bereich
        self.image_capture = rectangle_grid(self.image_target.copy() if self.flag_filter else self.image_filter.copy(),
                                                tuple(self.roi_filter[0] if self.flag_filter else self.roi_target[0]),
                                                tuple(self.roi_filter[1] if self.flag_filter else self.roi_target[1]),
                                                color,
                                                cols, rows,
                                                1)
        cv2.destroyWindow("set ROI")

    #Zeichnen Sie, während Sie darauf achten, keinen Fehler zu verursachen, wenn die Größe 0 ist
    def draw_shape(self, event, x, y, flag, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            self.drawing = True
            self.roi_temp[0][1] = y
            self.roi_temp[0][0] = x

        elif event == cv2.EVENT_MOUSEMOVE:
            if self.flag_filter: #Gibt es einen klügeren Weg?
                if not (self.roi_filter[0][0] == x or self.roi_filter[0][1] == y) and self.drawing == True:
                        self.roi_filter = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)
            else:
                if not (self.roi_target[0][0] == x or self.roi_target[0][1] == y) and self.drawing == True:
                        self.roi_target = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)

        elif event == cv2.EVENT_LBUTTONUP:
            self.drawing = False
            if self.flag_filter:
                if not (self.roi_filter[0][0] == x or self.roi_filter[0][1] == y):
                    self.roi_filter = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)
            else:
                if not (self.roi_target[0][0] == x or self.roi_target[0][1] == y):
                    self.roi_target = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)

            self.flag_drawing = False

    # https://qiita.com/dario_okazaki/items/656de21cab5c81cabe59
    def main(self):
        #Abschnitt 1-Optionseinstellungen und Standardlayout
        sg.theme('Dark Blue 3')

        # filter frame
        filter_box = sg.Frame('FILTER', font='Any 15', layout=[
                    [sg.Text('kernelsize_col'), sg.Input("3", size=(3,None), key='kernelsize_0')],
                    [sg.Text('kernelsize_row'), sg.Input("3", size=(3,None), key='kernelsize_1')],
                    [sg.Button('filter', key='filter')],
                    [sg.Image(filename='', key='image_filter')],
                    [sg.Multiline('[0.0, 0.1, 0.2],\n[0.1, 0.2, 0.4],\n[0.0, 0.2, 0.4]', size=(24, 12), key='filterarray')],
                    ])

        target_box = sg.Frame('TARGET', font='Any 15', layout=[
                    [sg.Text('targetsize_col'), sg.Input("5", size=(3,None), key='targetsize_0')],
                    [sg.Text('targetsize_row'), sg.Input("5", size=(3,None), key='targetsize_1')],
                    [sg.Button('target', key='target')],
                    [sg.Image(filename='', key='image_target')],
                    [sg.Multiline('[0.0, 2.0, 8.0, 3.0, 5.0],\n[5.0, 1.0, 7.0, 6.0, 3.0],\n[2.0, 9.0, 3.0, 2.0, 1.0],\n[5.0, 4.0, 1.0, 4.0, 8.0],\n[0.0, 5.0, 2.0, 8.0, 5.0]',size=(24, 12), key='targetarray')],
                    ])

        calculated_box = sg.Frame('CALCULATED', font='Any 15', layout=[
                    [sg.Text('stride'), sg.Input("2", size=(3,None), key='stride')],
                    [sg.Button('calculate', key='calculate')],
                    [sg.Multiline('calculated',size=(24, 12),key='text_calculated')],
                    ])

        layout = [
                # [sg.Text('Type the window name and press the button to capture it.\nIf it couldnt find the one, it will capture a whole area of a primary display.')],
                [sg.Text('Geben Sie den Fensternamen ein und klicken Sie auf die Schaltfläche\n Wenn nicht gefunden, erfassen Sie die Hauptanzeige so wie sie ist')],
                [sg.Input("FireFox", size=(40,None), key='windowname'), sg.Button('windowcapture', key='windowcapture')],
                [sg.Image(filename='', key='image_capture', size=(600,300), )],
                [filter_box, target_box, calculated_box],
                ]

        #Sektion 2-Fenstergenerierung
        self.window = sg.Window('ConvCalcOCR', layout)

        # init OCR
        tools = pyocr.get_available_tools()
        if len(tools) == 0:
            print("No OCR tool found")
            sys.exit(1)
        self.tool = tools[0]
        print("Will use tool '%s'" % (self.tool.get_name()))

        #Sektion 3-Ereignisschleife
        while True:
            event, values = self.window.read()

            if event is None:
                print('exit')
                break

            elif event == 'windowcapture':
                self.image_capture = cv2.cvtColor(WindowCapture(values['windowname']), cv2.COLOR_BGRA2BGR)
                self.image_copy = self.image_target = self.image_filter = self.image_capture.copy()
                img = scale_box(self.image_capture, 600, 300)
                imgbytes = cv2.imencode('.png', img)[1].tobytes()
                self.window['image_capture'].update(data=imgbytes)

            elif event == 'filter':
                self.flag_filter = True #Gibt es einen klügeren Weg?
                self.redefine_rectangle(int(values['kernelsize_0']), int(values['kernelsize_1']), (128, 128, 0))
                img = scale_box(self.image_capture, 600, 300)
                imgbytes = cv2.imencode('.png', img)[1].tobytes()
                self.window['image_capture'].update(data=imgbytes)

            elif event == 'target':
                self.flag_filter = False
                self.redefine_rectangle(int(values['targetsize_0']), int(values['targetsize_1']), (0, 0, 255))
                img = scale_box(self.image_capture, 600, 300)
                imgbytes = cv2.imencode('.png', img)[1].tobytes()
                self.window['image_capture'].update(data=imgbytes)

            elif event == 'calculate':
                calculated = strideConv(values['targetarray'], values['filterarray'], int(values['stride']))
                calculated = np.round(calculated, decimals=2) #Weil aufgrund von Berechnungsfehlern möglicherweise viele Zahlen nach dem Dezimalpunkt stehen
                calculated_shape = np.array(calculated).shape
                
                self.window['text_calculated'].update(fix_textbox(calculated.tolist(), calculated_shape[0], calculated_shape[1]))

        #Sektion 4-Fenster zerstören und schließen
        self.window.close()

Ausführungsergebnis

Rechteckige Zeichnung vom Rastertyp

Zeichnen Sie mit einem Raster, um die Anpassung des mit der Maus gezogenen Bereichs zu vereinfachen

#Rechteck mit Gitter
def rectangle_grid(img, pt1, pt2, color, cols, rows, thickness=1, lineType=cv2.LINE_8, shift=None):
    space_x = abs(pt2[0] - pt1[0]) / cols
    space_y = abs(pt2[1] - pt1[1]) / rows

    for col in range(cols+1):
        img = cv2.line(img, (int(pt1[0]+col*space_x), pt1[1]), (int(pt1[0]+col*space_x), pt2[1]), color, thickness, lineType)
    for row in range(rows+1):
        img = cv2.line(img, (pt1[0], int(pt1[1]+row*space_y)), (pt2[0], int(pt1[1]+row*space_y)), color, thickness, lineType)

    return img

Korrektur der Bereichsspezifikation durch Ziehen der Maus

Stellen Sie beim Festlegen des Bereichs durch Ziehen der Maus sicher, dass die Bildgröße zu Beginn des Zeichnens 0 wird und dass sie aufgrund des auftretenden Fehlers und der Addition und Subtraktion zum Zeitpunkt der Koordinatenberechnung nicht negativ wird (ich habe die Seite, auf die ich mich bezog, nicht notiert. Es tut mir Leid.)

#Negative Koordinatenunterstützung
def fix_coordinate(iy, ix, y, x):
    x_sorted = sorted([ix, x])
    y_sorted = sorted([iy, y])
    # relu
    return [[np.maximum(0, x_sorted[0]), np.maximum(0, y_sorted[0])],
            [np.maximum(0, x_sorted[1]), np.maximum(0, y_sorted[1])]]

Bildaufteilung

Teilen Sie das Bild in eine beliebige Zahl und entfernen Sie dann den Rand der Tabelle in der Problemstellung aus dem Bild, indem Sie den Umfang um das Erodierverhältnis schneiden.

#Bildaufteilung
def divide_image(image, roi, cols, rows, eroderatio):
    #Ernte
    cropped = image[roi[0][1]:roi[1][1], roi[0][0]:roi[1][0]]

    # https://pystyle.info/opencv-split-and-concat-images/
    chunks = []
    for row_cropped in np.array_split(cropped, rows, axis=0):
        for chunk in np.array_split(row_cropped, cols, axis=1):
            #Entfernen Sie Rahmen, die tendenziell als Zeichen beurteilt werden
            erode = int(eroderatio*min(chunk.shape[:2]))
            chunk = chunk[erode:chunk.shape[0]-erode, erode:chunk.shape[1]-erode]
            chunks.append(chunk)

    return chunks

Korrektur des gelesenen Zahlenwerts

Da "." Und "-" nicht normal gelesen werden können, werden sie einmal ignoriert und formatiert, indem angenommen wird, dass der ganzzahlige Teil im G-Test nur eine Ziffer ist.

#Formatierung unter der Annahme, dass der ganzzahlige Teil eine Ziffer ist
def fix_num(num):
    fixed_num = re.sub("\\D", "", num) #Andere als Zahlen löschen
    if fixed_num == '' or fixed_num == '-': # "-"Wurde als Nummer behandelt
        return 0.0
    else:
        fixed_num = fixed_num[0] + '.' + fixed_num[1:]
        return fixed_num

Bildschirmanzeige der gelesenen Zahlenwerte

Da die Liste der von OCR gelesenen numerischen Werte keinen Zeilenumbruch enthält und die Anzeige unverändert ist, zerlegen Sie den Zeilenumbruchcode und fügen Sie ihn ein.

#Formgebung für das Display
def fix_textbox(score_list, rows, cols):
    score_array = np.reshape(np.array(score_list), (rows, cols))
    score_list_reshaped= ["{}".format(l) for l in score_array.tolist()]
    return ',\n'.join(score_list_reshaped)

Faltungsberechnung

Der von OCR gelesene numerische Wert wird nach Rückgabe von scipy berechnet, da die Klammern von List für die Bildschirmanzeige gelöscht werden.

#Faltungsberechnung
# https://stackoverflow.com/questions/48097941/strided-convolution-of-2d-in-numpy/48098534
def strideConv(v1, v2, s):
    arr = np.array(eval('[' + v1 + ']'))
    arr2 = np.array(eval('[' + v2 + ']'))

    return signal.convolve2d(arr, arr2[::-1, ::-1], mode='valid')[::s, ::s]

Ganzer Code

import sys
import PySimpleGUI as sg
import numpy as np
import cv2
import win32gui
import win32ui
import win32con
import pyocr
import re
from PIL import Image
from scipy import signal


#Da ich win32api verwende, funktioniert es unter Unix nicht so wie es ist
class ConvCalc():
    def __init__(self, **kwargs):
        self.drawing = False
        self.flag_drawing = False
        self.flag_filter = True
        self.roi_filter = [[0, 0], [50, 50]]
        self.roi_target = [[0, 0], [50, 50]]
        self.roi_temp = [[0, 0], [50, 50]]
        self.image_filter = np.zeros((300, 300, 3), np.uint8)
        self.image_target = np.zeros((300, 300, 3), np.uint8)
        self.image_capture = np.zeros((300, 300, 3), np.uint8)
        self.image_copy = np.zeros((300, 300, 3), np.uint8)
        self.tool = None

    #Beginnen Sie mit der Auswahl des Rechtecks
    def redefine_rectangle(self, cols, rows, color):
        cv2.namedWindow("set ROI")
        cv2.setMouseCallback("set ROI", self.draw_shape)
        self.flag_drawing = True

        while 1:
            image_rect = rectangle_grid(self.image_copy.copy(),
                                    tuple(self.roi_filter[0] if self.flag_filter else self.roi_target[0]),
                                    tuple(self.roi_filter[1] if self.flag_filter else self.roi_target[1]),
                                    color,
                                    cols, rows,
                                    1)

            cv2.imshow("set ROI", image_rect)
            cv2.waitKey(1)

            #× Tastenerkennung
            ret = cv2.getWindowProperty('set ROI', cv2.WND_PROP_ASPECT_RATIO)
            
            #Ich frage mich, ob ich mit dem Schreiben fertig sein oder mit der Taste × brechen und die Taste nicht verarbeiten soll
            if not self.flag_drawing or ret == -1.0:
                #Geteilte Bilderstellung
                divided_image = divide_image(self.image_copy, self.roi_filter if self.flag_filter else self.roi_target, cols, rows, 0.08)
                score_list = []
                for c, divided in enumerate(divided_image):
                    txt = self.tool.image_to_string(
                        Image.fromarray(cv2.cvtColor(divided, cv2.COLOR_BGR2RGB)),
                        lang="eng",
                        # builder=pyocr.builders.TextBuilder(tesseract_layout=6),
                        builder=pyocr.tesseract.DigitBuilder(tesseract_layout=6),
                    )
                    score_list.append(float(fix_num(txt)))

                #Umformen auf die Dimension von Rowcol
                score_list_reshaped = fix_textbox(score_list, rows, cols)

                #Reflektieren Sie den erkannten Zahlenwert
                if self.flag_filter:
                    self.image_filter = image_rect
                    self.window['filterarray'].update(score_list_reshaped)
                else:
                    self.image_target = image_rect
                    self.window['targetarray'].update(score_list_reshaped)

                break
        
        #Zeichnen Sie den endgültigen Bereich
        self.image_capture = rectangle_grid(self.image_target.copy() if self.flag_filter else self.image_filter.copy(),
                                                tuple(self.roi_filter[0] if self.flag_filter else self.roi_target[0]),
                                                tuple(self.roi_filter[1] if self.flag_filter else self.roi_target[1]),
                                                color,
                                                cols, rows,
                                                1)
        cv2.destroyWindow("set ROI")

    #Zeichnen Sie, während Sie darauf achten, keinen Fehler zu verursachen, wenn die Größe 0 ist
    def draw_shape(self, event, x, y, flag, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            self.drawing = True
            self.roi_temp[0][1] = y
            self.roi_temp[0][0] = x

        elif event == cv2.EVENT_MOUSEMOVE:
            if self.flag_filter: #Gibt es einen klügeren Weg?
                if not (self.roi_filter[0][0] == x or self.roi_filter[0][1] == y) and self.drawing == True:
                        self.roi_filter = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)
            else:
                if not (self.roi_target[0][0] == x or self.roi_target[0][1] == y) and self.drawing == True:
                        self.roi_target = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)

        elif event == cv2.EVENT_LBUTTONUP:
            self.drawing = False
            if self.flag_filter:
                if not (self.roi_filter[0][0] == x or self.roi_filter[0][1] == y):
                    self.roi_filter = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)
            else:
                if not (self.roi_target[0][0] == x or self.roi_target[0][1] == y):
                    self.roi_target = fix_coordinate(self.roi_temp[0][1], self.roi_temp[0][0], y, x)

            self.flag_drawing = False

    # https://qiita.com/dario_okazaki/items/656de21cab5c81cabe59
    def main(self):
        #Abschnitt 1-Optionseinstellungen und Standardlayout
        sg.theme('Dark Blue 3')

        # filter frame
        filter_box = sg.Frame('FILTER', font='Any 15', layout=[
                    [sg.Text('kernelsize_col'), sg.Input("3", size=(3,None), key='kernelsize_0')],
                    [sg.Text('kernelsize_row'), sg.Input("3", size=(3,None), key='kernelsize_1')],
                    [sg.Button('filter', key='filter')],
                    [sg.Image(filename='', key='image_filter')],
                    [sg.Multiline('[0.0, 0.1, 0.2],\n[0.1, 0.2, 0.4],\n[0.0, 0.2, 0.4]', size=(24, 12), key='filterarray')],
                    ])

        target_box = sg.Frame('TARGET', font='Any 15', layout=[
                    [sg.Text('targetsize_col'), sg.Input("5", size=(3,None), key='targetsize_0')],
                    [sg.Text('targetsize_row'), sg.Input("5", size=(3,None), key='targetsize_1')],
                    [sg.Button('target', key='target')],
                    [sg.Image(filename='', key='image_target')],
                    [sg.Multiline('[0.0, 2.0, 8.0, 3.0, 5.0],\n[5.0, 1.0, 7.0, 6.0, 3.0],\n[2.0, 9.0, 3.0, 2.0, 1.0],\n[5.0, 4.0, 1.0, 4.0, 8.0],\n[0.0, 5.0, 2.0, 8.0, 5.0]',size=(24, 12), key='targetarray')],
                    ])

        calculated_box = sg.Frame('CALCULATED', font='Any 15', layout=[
                    [sg.Text('stride'), sg.Input("2", size=(3,None), key='stride')],
                    [sg.Button('calculate', key='calculate')],
                    [sg.Multiline('calculated',size=(24, 12),key='text_calculated')],
                    ])

        layout = [
                # [sg.Text('Type the window name and press the button to capture it.\nIf it couldnt find the one, it will capture a whole area of a primary display.')],
                [sg.Text('Geben Sie den Fensternamen ein und klicken Sie auf die Schaltfläche\n Wenn nicht gefunden, erfassen Sie die Hauptanzeige so wie sie ist')],
                [sg.Input("FireFox", size=(40,None), key='windowname'), sg.Button('windowcapture', key='windowcapture')],
                [sg.Image(filename='', key='image_capture', size=(600,300), )],
                [filter_box, target_box, calculated_box],
                ]

        #Sektion 2-Fenstergenerierung
        self.window = sg.Window('ConvCalcOCR', layout)

        # init OCR
        tools = pyocr.get_available_tools()
        if len(tools) == 0:
            print("No OCR tool found")
            sys.exit(1)
        self.tool = tools[0]
        print("Will use tool '%s'" % (self.tool.get_name()))

        #Sektion 3-Ereignisschleife
        while True:
            event, values = self.window.read()

            if event is None:
                print('exit')
                break

            elif event == 'windowcapture':
                self.image_capture = cv2.cvtColor(WindowCapture(values['windowname']), cv2.COLOR_BGRA2BGR)
                self.image_copy = self.image_target = self.image_filter = self.image_capture.copy()
                img = scale_box(self.image_capture, 600, 300)
                imgbytes = cv2.imencode('.png', img)[1].tobytes()
                self.window['image_capture'].update(data=imgbytes)

            elif event == 'filter':
                self.flag_filter = True #Gibt es einen klügeren Weg?
                self.redefine_rectangle(int(values['kernelsize_0']), int(values['kernelsize_1']), (128, 128, 0))
                img = scale_box(self.image_capture, 600, 300)
                imgbytes = cv2.imencode('.png', img)[1].tobytes()
                self.window['image_capture'].update(data=imgbytes)

            elif event == 'target':
                self.flag_filter = False
                self.redefine_rectangle(int(values['targetsize_0']), int(values['targetsize_1']), (0, 0, 255))
                img = scale_box(self.image_capture, 600, 300)
                imgbytes = cv2.imencode('.png', img)[1].tobytes()
                self.window['image_capture'].update(data=imgbytes)

            elif event == 'calculate':
                calculated = strideConv(values['targetarray'], values['filterarray'], int(values['stride']))
                calculated = np.round(calculated, decimals=2) #Weil aufgrund von Berechnungsfehlern möglicherweise viele Zahlen nach dem Dezimalpunkt stehen
                calculated_shape = np.array(calculated).shape
                
                self.window['text_calculated'].update(fix_textbox(calculated.tolist(), calculated_shape[0], calculated_shape[1]))

        #Sektion 4-Fenster zerstören und schließen
        self.window.close()


#Rechteck mit Gitter
def rectangle_grid(img, pt1, pt2, color, cols, rows, thickness=1, lineType=cv2.LINE_8, shift=None):
    space_x = abs(pt2[0] - pt1[0]) / cols
    space_y = abs(pt2[1] - pt1[1]) / rows

    for col in range(cols+1):
        img = cv2.line(img, (int(pt1[0]+col*space_x), pt1[1]), (int(pt1[0]+col*space_x), pt2[1]), color, thickness, lineType)
    for row in range(rows+1):
        img = cv2.line(img, (pt1[0], int(pt1[1]+row*space_y)), (pt2[0], int(pt1[1]+row*space_y)), color, thickness, lineType)

    return img


#Bildaufteilung
def divide_image(image, roi, cols, rows, eroderatio):
    #Ernte
    cropped = image[roi[0][1]:roi[1][1], roi[0][0]:roi[1][0]]

    # https://pystyle.info/opencv-split-and-concat-images/
    chunks = []
    for row_cropped in np.array_split(cropped, rows, axis=0):
        for chunk in np.array_split(row_cropped, cols, axis=1):
            #Entfernen Sie Rahmen, die tendenziell als Zeichen beurteilt werden
            erode = int(eroderatio*min(chunk.shape[:2]))
            chunk = chunk[erode:chunk.shape[0]-erode, erode:chunk.shape[1]-erode]
            chunks.append(chunk)

    return chunks


#Negative Koordinatenunterstützung
def fix_coordinate(iy, ix, y, x):
    x_sorted = sorted([ix, x])
    y_sorted = sorted([iy, y])
    # relu
    return [[np.maximum(0, x_sorted[0]), np.maximum(0, y_sorted[0])],
            [np.maximum(0, x_sorted[1]), np.maximum(0, y_sorted[1])]]


#Formatierung unter der Annahme, dass der ganzzahlige Teil eine Ziffer ist
def fix_num(num):
    fixed_num = re.sub("\\D", "", num) #Andere als Zahlen löschen
    if fixed_num == '' or fixed_num == '-': # "-"Wurde als Nummer behandelt
        return 0.0
    else:
        fixed_num = fixed_num[0] + '.' + fixed_num[1:]
        return fixed_num


#Formgebung für das Display
def fix_textbox(score_list, rows, cols):
    score_array = np.reshape(np.array(score_list), (rows, cols))
    score_list_reshaped= ["{}".format(l) for l in score_array.tolist()]
    return ',\n'.join(score_list_reshaped)


#Bildgröße ändern
# https://pystyle.info/opencv-resize/#outline__3_5
def scale_box(img, width, height):
    """Korrigieren Sie das Seitenverhältnis und ändern Sie die Größe so, dass es in die angegebene Größe passt.
    """
    h, w = img.shape[:2]
    aspect = w / h
    if width / height >= aspect:
        nh = height
        nw = round(nh * aspect)
    else:
        nw = width
        nh = round(nw / aspect)

    return cv2.resize(img, dsize=(nw, nh))


#Faltungsberechnung
# https://stackoverflow.com/questions/48097941/strided-convolution-of-2d-in-numpy/48098534
def strideConv(v1, v2, s):
    arr = np.array(eval('[' + v1 + ']'))
    arr2 = np.array(eval('[' + v2 + ']'))

    return signal.convolve2d(arr, arr2[::-1, ::-1], mode='valid')[::s, ::s]


#Fenstererfassung
# https://qiita.com/danupo/items/e196e0e07e704796cd42
def WindowCapture(window_name: str, bgr2rgb: bool = False):
    #Suchen Sie den Namen des aktuell aktiven Fensters
    process_list = []

    def callback(handle, _):
        process_list.append(win32gui.GetWindowText(handle))

    win32gui.EnumWindows(callback, None)

    #Suchen Sie den Namen des Zielfensters
    for process_name in process_list:
        if window_name in process_name:
            hnd = win32gui.FindWindow(None, process_name)
            break
    else:
        #Holen Sie sich den gesamten Bildschirm, wenn nicht gefunden
        hnd = win32gui.GetDesktopWindow()

    #Fenstergröße abrufen
    x0, y0, x1, y1 = win32gui.GetWindowRect(hnd)
    width = x1 - x0
    height = y1 - y0
    #Gerätekontext für ein Fenster abrufen
    windc = win32gui.GetWindowDC(hnd)
    srcdc = win32ui.CreateDCFromHandle(windc)
    memdc = srcdc.CreateCompatibleDC()
    #Kopieren Sie Pixelinformationen aus dem Gerätekontext,BMP-Konvertierung
    bmp = win32ui.CreateBitmap()
    bmp.CreateCompatibleBitmap(srcdc, width, height)
    memdc.SelectObject(bmp)
    memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)

    #Exportieren Sie bmp
    if bgr2rgb is True: 
        img = np.frombuffer(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
        img = cv2.cvtColor(img, cv2.COLOR_bgr2rgb)
    else:
        img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)

    #Aufräumen
    # srcdc.DeleteDC()
    memdc.DeleteDC()
    # win32gui.ReleaseDC(hnd, windc)
    win32gui.DeleteObject(bmp.GetHandle())

    return img


if __name__ == '__main__':
    ConvCalc().main()

Referenz

Schließlich

――Ich denke, es gibt viele Orte, die nicht erreichbar sind, also zögern Sie nicht, darauf hinzuweisen. ――Wie viele Faltungsberechnungen werden im G-Test abgefragt? ――Ich denke, ich hätte die Zeit studieren sollen, als ich das gemacht habe. ――Nächste möchte ich einen Artikel über Kivy schreiben.

Nachtrag

In der Prüfung 2020.11.7 habe ich keine einzige Frage zur Faltungsberechnung erhalten: wütend:

Recommended Posts

G-Test misst das OCR-Faltungsberechnungswerkzeug