Ceci est le premier message. J'ai contesté si je pouvais en quelque sorte automatiser le calcul de convolution de la rumeur lors de sa sortie avec le test G. Je ne pense pas que ce soit un calcul que les humains font de leur mieux.
Intérieurement --PySimpleGUI (je voulais vraiment utiliser Kivy)
Le code est également ci-dessous. https://github.com/poohsanforest/ConvCalcOCR
Image de test (ouverte dans Firefox)
Je crée une partie GUI avec PySimpleGUI. Les fonctions redefine_rectangle et draw_shape peuvent être utiles lors de la récupération des coordonnées en faisant glisser la souris.
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
#Puisque j'utilise win32api, cela ne fonctionnera pas avec unix tel quel
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
#Commencer à sélectionner le rectangle
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)
#× Détection de bouton
ret = cv2.getWindowProperty('set ROI', cv2.WND_PROP_ASPECT_RATIO)
#Je me demande si je devrais finir d'écrire ou interrompre avec le bouton × et ne pas traiter le bouton
if not self.flag_drawing or ret == -1.0:
#Création d'image fractionnée
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)))
#Remodeler à la dimension de rowcol
score_list_reshaped = fix_textbox(score_list, rows, cols)
#Refléter la valeur numérique reconnue
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
#Dessinez la plage finale
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")
#Dessinez en prenant soin de ne pas provoquer d'erreur lorsque la taille est de 0
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: #Existe-t-il un moyen plus intelligent?
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):
#Section 1-Paramètres des options et disposition standard
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('Entrez le nom de la fenêtre et cliquez sur le bouton\n S'il n'est pas trouvé, capturez l'écran principal tel quel')],
[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],
]
#Section 2-Génération de fenêtres
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()))
#Section 3-Boucle d'événement
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 #Existe-t-il un moyen plus intelligent?
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) #Parce qu'il peut y avoir plusieurs nombres après la virgule décimale en raison d'une erreur de calcul
calculated_shape = np.array(calculated).shape
self.window['text_calculated'].update(fix_textbox(calculated.tolist(), calculated_shape[0], calculated_shape[1]))
#Section 4-Détruire et fermer les fenêtres
self.window.close()
Résultat d'exécution
Dessinez avec une grille pour faciliter la correspondance avec la plage déplacée avec la souris
#Rectangle avec grille
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
Lorsque vous spécifiez la plage en faisant glisser la souris, assurez-vous que la taille de l'image devient 0 au début du dessin et qu'elle ne devient pas négative en raison de l'erreur qui se produit et de l'addition et de la soustraction au moment du calcul des coordonnées (je n'ai pas noté la page à laquelle je faisais référence. Je suis désolé.)
#Support de coordonnées négatives
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])]]
Divisez l'image en un nombre quelconque, puis supprimez la bordure du tableau dans l'énoncé du problème de l'image en coupant la circonférence par le rapport d'érosion.
#Image fractionnée
def divide_image(image, roi, cols, rows, eroderatio):
#Surgir
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):
#Supprimer les bordures qui ont tendance à être considérées comme des caractères
erode = int(eroderatio*min(chunk.shape[:2]))
chunk = chunk[erode:chunk.shape[0]-erode, erode:chunk.shape[1]-erode]
chunks.append(chunk)
return chunks
Puisque "." Et "-" ne peuvent pas être lus normalement, ils sont ignorés une fois et formatés en supposant que la partie entière n'a qu'un seul chiffre dans le test G.
#Mise en forme en supposant que la partie entière est un chiffre
def fix_num(num):
fixed_num = re.sub("\\D", "", num) #Supprimer autre que des nombres
if fixed_num == '' or fixed_num == '-': # "-"A été traité comme un nombre
return 0.0
else:
fixed_num = fixed_num[0] + '.' + fixed_num[1:]
return fixed_num
Comme il n'y a pas de saut de ligne dans la liste des valeurs numériques lues par OCR et que l'affichage est interrompu tel quel, démontez et insérez le code de saut de ligne.
#Mise en forme pour l'affichage
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)
La valeur numérique lue par OCR est calculée par scipy après l'avoir renvoyée car les parenthèses de List sont supprimées pour l'affichage à l'écran
#Calcul de la convolution
# 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]
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
#Puisque j'utilise win32api, cela ne fonctionnera pas avec unix tel quel
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
#Commencer à sélectionner le rectangle
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)
#× Détection de bouton
ret = cv2.getWindowProperty('set ROI', cv2.WND_PROP_ASPECT_RATIO)
#Je me demande si je devrais finir d'écrire ou interrompre avec le bouton × et ne pas traiter le bouton
if not self.flag_drawing or ret == -1.0:
#Création d'image fractionnée
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)))
#Remodeler à la dimension de rowcol
score_list_reshaped = fix_textbox(score_list, rows, cols)
#Refléter la valeur numérique reconnue
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
#Dessinez la plage finale
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")
#Dessinez en prenant soin de ne pas provoquer d'erreur lorsque la taille est de 0
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: #Existe-t-il un moyen plus intelligent?
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):
#Section 1-Paramètres des options et disposition standard
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('Entrez le nom de la fenêtre et cliquez sur le bouton\n S'il n'est pas trouvé, capturez l'écran principal tel quel')],
[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],
]
#Section 2-Génération de fenêtres
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()))
#Section 3-Boucle d'événement
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 #Existe-t-il un moyen plus intelligent?
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) #Parce qu'il peut y avoir plusieurs nombres après la virgule décimale en raison d'une erreur de calcul
calculated_shape = np.array(calculated).shape
self.window['text_calculated'].update(fix_textbox(calculated.tolist(), calculated_shape[0], calculated_shape[1]))
#Section 4-Détruire et fermer les fenêtres
self.window.close()
#Rectangle avec grille
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
#Image fractionnée
def divide_image(image, roi, cols, rows, eroderatio):
#Surgir
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):
#Supprimer les bordures qui ont tendance à être considérées comme des caractères
erode = int(eroderatio*min(chunk.shape[:2]))
chunk = chunk[erode:chunk.shape[0]-erode, erode:chunk.shape[1]-erode]
chunks.append(chunk)
return chunks
#Support de coordonnées négatives
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])]]
#Mise en forme en supposant que la partie entière est un chiffre
def fix_num(num):
fixed_num = re.sub("\\D", "", num) #Supprimer autre que des nombres
if fixed_num == '' or fixed_num == '-': # "-"A été traité comme un nombre
return 0.0
else:
fixed_num = fixed_num[0] + '.' + fixed_num[1:]
return fixed_num
#Mise en forme pour l'affichage
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)
#Redimensionnement de l'image
# https://pystyle.info/opencv-resize/#outline__3_5
def scale_box(img, width, height):
"""Fixez le rapport hauteur / largeur et redimensionnez-le pour qu'il tienne dans la taille spécifiée.
"""
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))
#Calcul de la convolution
# 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]
#Capture de fenêtre
# https://qiita.com/danupo/items/e196e0e07e704796cd42
def WindowCapture(window_name: str, bgr2rgb: bool = False):
#Trouvez le nom de la fenêtre actuellement active
process_list = []
def callback(handle, _):
process_list.append(win32gui.GetWindowText(handle))
win32gui.EnumWindows(callback, None)
#Trouvez le nom de la fenêtre cible
for process_name in process_list:
if window_name in process_name:
hnd = win32gui.FindWindow(None, process_name)
break
else:
#Obtenez l'écran entier s'il n'est pas trouvé
hnd = win32gui.GetDesktopWindow()
#Obtenir la taille de la fenêtre
x0, y0, x1, y1 = win32gui.GetWindowRect(hnd)
width = x1 - x0
height = y1 - y0
#Obtenir le contexte de l'appareil pour une fenêtre
windc = win32gui.GetWindowDC(hnd)
srcdc = win32ui.CreateDCFromHandle(windc)
memdc = srcdc.CreateCompatibleDC()
#Copier les informations de pixel à partir du contexte de l'appareil,conversion bmp
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, width, height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)
#Exporter 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)
#Nettoyer
# srcdc.DeleteDC()
memdc.DeleteDC()
# win32gui.ReleaseDC(hnd, windc)
win32gui.DeleteObject(bmp.GetHandle())
return img
if __name__ == '__main__':
ConvCalc().main()
«Je pense qu'il y a de nombreux endroits qui ne peuvent être atteints, alors n'hésitez pas à le signaler. ―― Combien de calculs de convolution seront demandés dans le test G? «Je pense que j'aurais dû étudier le moment où je faisais ça. ―― Ensuite, je voudrais faire un article sur Kivy.
Lors de l'examen 2020.11.7, je n'ai pas reçu une seule question de calcul de convolution: en colère:
Recommended Posts