A continué Essayez de créer un logiciel de capture aussi précis que possible avec python (2) https://qiita.com/akaiteto/items/56bfd8d764d42b9ff508 Essayez de créer un logiciel de capture aussi précis que possible avec python (1) https://qiita.com/akaiteto/items/b2119260d732bb189c87
J'en ai assez de la capture d'écran et audio, alors je vais faire une autre partie. Le processus suivant est un processus approximatif actuellement envisagé.
Cette fois, je ferai la deuxième partie. Je souhaite soutenir de manière flexible toute structure du site Web Le but est de faire fonctionner le navigateur avec la détection d'images opencv sans analyser le HTML.
J'ai ajouté la raison de la modernisation, mais ... Puisque l'écran est pressé, je veux juste traiter l'image.
1. 1. Transition vers la destination de l'URL
2. Appuyez sur le bouton de lecture
3. 3. Détecter la zone de la carte météo
4. Enregistrer la zone détectée
Imaginez un site qui propose une vidéo d'une carte météo. L'ensemble du processus est supposé comme ci-dessus. Cette fois, ce sera probablement 1-3.
OS : windows10 ver: python3.7 web: chrome
Selenium
Utilisons Selenium, une bibliothèque qui vous permet de faire fonctionner le navigateur à partir de commandes. https://qiita.com/hanzawak/items/2ab4d2a333d6be6ac760 https://rabbitfoot.xyz/selenium-chrome-profile/
En passant, j'utilise Chrome + pycharm, donc Lors de l'installation du pilote Web, installez-le dans l'environnement virtuel python.
#Installation dans un environnement virtuel
cd D:~ Omis ~\venv\Scripts
bat activate.bat
pip install chromedriver-binary==(La version de Chrome que vous utilisez)
Affichez le site de la carte météo. Enregistrez également l'image capturée du chrome ouvert pour les étapes ultérieures. Si vous utilisez la source ci-dessous, veuillez remplir la section (votre nom d'utilisateur). Pour plus de détails sur le chemin du profil, voir https://rabbitfoot.xyz/selenium-chrome-profile/
from selenium import webdriver
import chromedriver_binary #Important
from selenium.webdriver.chrome.options import Options
import win32gui
import win32ui
import win32con
import numpy as np
import cv2
#Obtenez un écran en taille réelle
hnd = win32gui.GetDesktopWindow()
x0, y0, x1, y1 = win32gui.GetWindowRect(hnd)
fullscreen_width = x1 - x0
fullscreen_height = y1 - y0
#Taille du navigateur
browse_width=300
browse_height=fullscreen_height
#Lancer le navigateur
options = Options()
options.add_argument(r"--user-data-dir=C:\Users\(Ton nom d'utilisateur)\AppData\Local\Google\Chrome\User Data")
driver = webdriver.Chrome(chrome_options=options)
driver.get("url")
driver.set_window_size(browse_width,browse_height)
driver.set_window_position(0,0)
#Capture d'écran du navigateur
windc = win32gui.GetWindowDC(hnd)
srcdc = win32ui.CreateDCFromHandle(windc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, browse_width, browse_height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, 'PointDetect.bmp')
# driver.close()
Lors de l'ouverture d'un site nécessitant une connexion. Je ne veux pas écrire mon propre code brut de mot de passe parce que je ne l'aime pas physiologiquement.
** Si le site nécessite une connexion, connectez-vous à l'avance depuis Chrome **
user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir
À propos, l'erreur ci-dessus se produit lors de l'exécution avec Chrome en cours d'exécution. Vous pouvez prendre des mesures, mais cette fois, il n'est pas nécessaire de démarrer plusieurs chromes, donc je ne le ferai pas.
Détectons le bouton par traitement d'image et cliquons dessus.
Comme aperçu du processus, Obtenez les coordonnées du bouton de lecture et cliquez sur les coordonnées dans la bibliothèque pyautogui. Le problème est d'obtenir les coordonnées du bouton de lecture. Les deux propositions suivantes doivent être examinées.
1. 1. Détectez la forme et obtenez les coordonnées
2. Trouver la même partie que l'image du bouton de lecture
1. 1. Détectez la forme et obtenez les coordonnées
Faisons-le facilement avec la fonction opencv.
DetectTriangle.py
import cv2
import numpy as np
def DetectTriangle(img, inputNm, outputNm):
image_obj = cv2.imread(inputNm)
img = cv2.adaptiveThreshold(img, 255, 1, 1, 11, 2)
cv2.imwrite("PointDetect_threshold" + outputNm, img)
contours, hierarchy = cv2.findContours(img,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
for cnt in contours:
approx = cv2.approxPolyDP(cnt, 0.1 * cv2.arcLength(cnt, True), True)
# approx = cv2.approxPolyDP(cnt, 0.07 * cv2.arcLength(cnt, True), True) #Paramètres: affecte la précision
# approx = cv2.approxPolyDP(cnt, .03 * cv2.arcLength(cnt, True), True) #Paramètres: affecte la précision
# approx = cv2.approxPolyDP(cnt, .009 * cv2.arcLength(cnt, True), True) #Paramètres: affecte la précision
if len(approx) == 3:
print("triangle")
cv2.drawContours(image_obj, [cnt], 0, (0, 0, 255), -1)
elif len(approx) == 4:
print("square")
cv2.drawContours(image_obj, [cnt], 0, (0, 255, 0), -1)
elif len(approx) == 8:
print("circle")
area = cv2.contourArea(cnt)
(cx, cy), radius = cv2.minEnclosingCircle(cnt)
circleArea = radius * radius * np.pi
if circleArea == area:
cv2.drawContours(image_obj, [cnt], 0, (255, 0, 0), -1)
cv2.imwrite(outputNm, image_obj)
inputNm = 'PointDetect2.bmp'
srcImage = cv2.imread(inputNm)
gray = cv2.cvtColor(srcImage, cv2.COLOR_BGR2GRAY)
cv2.imwrite("PointDetect_gray.png ", gray)
kernel = np.ones((4, 4), np.uint8)
dilation = cv2.dilate(gray, kernel, iterations=1)
cv2.imwrite("PointDetect_dilation.png ", dilation)
blur = cv2.GaussianBlur(dilation, (5, 5), 0)
cv2.imwrite("PointDetect_blur.png ", dilation)
DetectTriangle(blur,inputNm,"result_blur.png ") #Brouiller
DetectTriangle(gray,inputNm,"result_gray.png ") #niveaux de gris
DetectTriangle(dilation,inputNm,"result_dilation.png ") #Gonfler (car le bouton de lecture est petit)
Le traitement que vous souhaitez effectuer est à peu près le suivant.
1. 1. Prétraitement
2. Traitement des seuils
3. 3. Extraction de contour
Je vais l'essayer avec la recherche d'images google sukusho.
Échelle de gris comme prétraitement ↓ (je fais diverses autres choses dans la source)
Traitement des seuils ↓
Extraction de contour ↓
Le rouge est un triangle, le vert est un carré et le bleu est un cercle. A partir des coordonnées du contour de la figure détecté ici C'est un calcul pour spécifier la position du bouton de lecture, qui est une forme de triangle.
・ ・ ・ ・ ・ ・
Alors, je suis allé sur le site météo. Le résultat n'était ... pas bon. J'ai essayé du flou, de l'expansion, du réglage des paramètres, etc., mais cela n'a pas fonctionné.
Le bouton de lecture a également été détecté, mais il y a trop de faux positifs. En premier lieu, il ne convient pas aux sites comportant de nombreuses figures triangulaires, Un autre inconvénient est que vous devrez peut-être ajuster les paramètres appropriés pour chaque site.
Il serait possible de détecter spécifiquement ce site météorologique, Je veux en faire un format qui puisse être fait sur différents sites, donc le plan 1 est rejeté.
2. Trouver la même partie que l'image du bouton de lecture
Je vais essayer de le détecter par correspondance de modèle. C'est un processus pour détecter si la même chose qu'une petite image est contenue dans une autre image. Pour effectuer une correspondance de modèles, il est nécessaire d'indiquer à l'image du bouton de lecture que la réponse est correcte.
Donc, sous le flux ci-dessus, Ajoutez une phase appelée "Obtenir l'image du bouton de lecture (manuel)". Je voulais tout faire automatiquement, mais cela ne peut pas être aidé.
Référence: https://shizenkarasuzon.hatenablog.com/entry/2020/03/23/005440
Imagewise Une petite fenêtre comme celle ci-dessus apparaîtra et l'utilisateur sélectionnera le bouton sur lequel il souhaite cliquer dans la fenêtre de sélection carrée (bleu clair). Enregistrez l'image pour le modèle correspondant à l'image de ... Le fonctionnement manuel n'est supposé que pour la première fois.
Je vais donc essayer la correspondance de modèles.
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html
Quand je l'ai exécuté selon la source de l'échantillon openCV, cela a très bien fonctionné. Allons-y avec la politique de 2
Je joue avec l'absdiff d'opencv (divers) Effectue une détection de mouvement sur les images avant et après avoir appuyé sur le bouton de lecture, Détecte la zone de changement.
Je vais résumer les sources jusqu'à présent.
Comme prémisse, l'image de la pièce sur laquelle vous voulez cliquer, Supposons que vous ayez déjà une image du bouton de lecture ici. ↓ Découpez l'image comme ci-dessous
Avant d'exécuter, installez les bibliothèques suivantes.
pip install PyAutoGUI
Dans mon environnement, l'erreur suivante s'est produite et l'installation a échoué.
SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0x93 in position 0: invalid start byte (sitecustomize.py, line 7)
https://qiita.com/hisakichi95/items/41002333efa8f6371d40 J'ai installé une ancienne version de PyMsgBox en faisant référence à.
Donc, la source suivante. Je ne l'organise pas
Detect.py
from selenium import webdriver
import chromedriver_binary #Important
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import win32gui
import win32ui
import win32con
import numpy as np
import cv2
def DetectMotion(ImgNm1,ImgNm2):
img1 = cv2.imread(ImgNm1, 0)
img2 = cv2.imread(ImgNm2, 0)
img1 = img1.copy().astype("float")
cv2.accumulateWeighted(img2, img1, 0.6)
cv2.accumulateWeighted(img2, img1, 0.6)
frameDelta = cv2.absdiff(img2, cv2.convertScaleAbs(img1))
thresh = cv2.threshold(frameDelta, 3, 255, cv2.THRESH_BINARY)[1]
contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img2 = cv2.imread(TEMP_AFTER_SCREENSHOT)
top_left_X = 9999999
top_left_Y = 9999999
bum_right_X = 0
bum_right_Y = 0
for i in range(0, len(contours)):
if len(contours[i]) > 0:
# remove small objects
if cv2.contourArea(contours[i]) < 500:
continue
rect = contours[i]
x, y, w, h = cv2.boundingRect(rect)
pos_top = (x, y)
pos_bum = (x + w, y + h)
print(x, y, x + w, y + h)
top_left_X = pos_top[0] if top_left_X > pos_top[0] else top_left_X
top_left_Y = pos_top[1] if top_left_Y > pos_top[1] else top_left_Y
bum_right_X = pos_bum[0] if bum_right_X < pos_bum[0] else bum_right_X
bum_right_Y = pos_bum[1] if bum_right_Y < pos_bum[1] else bum_right_Y
return (top_left_X, top_left_Y), (bum_right_X, bum_right_Y)
def DiffImage(img1,img2):
im_diff = img1.astype(int) - img2.astype(int)
im_diff_abs = np.abs(im_diff)
return im_diff_abs.max()
def DetectBtn(bmp,memdc,CapFIleNm,PatchNm,scrollY):
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, CapFIleNm)
#Obtenir les coordonnées du bouton
img = cv2.imread(CapFIleNm, 0)
img2 = img.copy()
template = cv2.imread(PatchNm, 0)
w, h = template.shape[::-1]
meth = 'cv2.TM_CCOEFF_NORMED'
img = img2.copy()
method = eval(meth)
res = cv2.matchTemplate(img, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img, top_left, bottom_right, 255, 2)
range = ((bottom_right[0] - top_left[0]) / 2, (bottom_right[1] - top_left[1]) / 2)
btn_center = (int(top_left[0] + range[0]), int(top_left[1] + range[1]))
print("Coordonnées en haut à gauche du bouton", top_left)
print("Coordonnées en haut à droite du bouton", bottom_right)
print("Coordonnées du centre du bouton", btn_center)
#Découpez la partie détectée
img1 = img[top_left[1]: bottom_right[1], top_left[0]: bottom_right[0]]
if DiffImage(template,img1) > 180:
#Trop différent de l'image du bouton-> False
cv2.imwrite("Detect_Fail" + str(scrollY) + ".jpg ", img1)
print("btn not exist")
return False,(0,0)
else:
#Succès-> True
cv2.imwrite("Detect_Success" + str(scrollY) + ".jpg ", img1)
print("btn exist")
return True,btn_center
TEMP_BEFORE_SCREENSHOT = 'PointDetect_before.bmp'
TEMP_AFTER_SCREENSHOT = 'PointDetect_after.bmp'
TEMP_PATCH = 'PointDetect_patch.jpg'
#Obtenez un écran en taille réelle
hnd = win32gui.GetDesktopWindow()
x0, y0, x1, y1 = win32gui.GetWindowRect(hnd)
fullscreen_width = x1 - x0
fullscreen_height = y1 - y0
#Taille du navigateur
# browse_width=fullscreen_width
# browse_height=fullscreen_height
browse_width=1920
browse_height=1080
#Lancer le navigateur
options = Options()
# options.add_argument(r"--user-data-dir=C:\Users\Ton nom d'utilisateur\AppData\Local\Google\Chrome\User Data")
driver = webdriver.Chrome(chrome_options=options)
driver.get("https://")
driver.set_window_size(browse_width,browse_height)
driver.set_window_position(0,0)
#En attente du comportement du navigateur
import time
time.sleep(3)
#Préparation Sukusho
windc = win32gui.GetWindowDC(hnd)
srcdc = win32ui.CreateDCFromHandle(windc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, browse_width, browse_height)
memdc.SelectObject(bmp)
#Faites défiler jusqu'à ce que vous trouviez le bouton
Detectflg=False
isScrolButton=False
scrollY = 0
while Detectflg==False:
scrollY += int(fullscreen_height/4)
#Obtenez une capture avant et après le défilement
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, TEMP_BEFORE_SCREENSHOT)
driver.execute_script("window.scrollTo(0, "+ str(scrollY) +")")
time.sleep(5)
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, TEMP_AFTER_SCREENSHOT)
img1 = cv2.imread(TEMP_BEFORE_SCREENSHOT, 0)
img2 = cv2.imread(TEMP_AFTER_SCREENSHOT, 0)
diff = DiffImage(img1,img2)
if diff < 100:
#L'écran ne change pas même si vous faites défiler->J'ai échoué parce que je suis arrivé au bas du rouleau
print("scrollbutton")
flg=True,btn_pos
isScrolButton=True
flg,btn_pos = DetectBtn(bmp,memdc,TEMP_AFTER_SCREENSHOT,TEMP_PATCH,scrollY)
Detectflg = flg
#Cliquez sur les coordonnées du bouton
if isScrolButton:
print("Bouton introuvable")
exit()
#Régénération
import pyautogui
pyautogui.click(btn_pos[0],btn_pos[1])
#Enregistrer avant le changement
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, TEMP_BEFORE_SCREENSHOT)
#Attendez que l'écran change
time.sleep(5)
#Enregistrer après modification
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, TEMP_AFTER_SCREENSHOT)
#Détection de mouvement
top_left,bottom_right = DetectMotion(TEMP_BEFORE_SCREENSHOT,TEMP_AFTER_SCREENSHOT)
img = cv2.imread(TEMP_AFTER_SCREENSHOT)
img1 = img[top_left[1]: bottom_right[1], top_left[0]: bottom_right[0]]
cv2.imwrite("MotionArea.jpg ", img1)
# driver.close()
Fonction de défilement pour trouver un bouton et Nous avons ajouté un processus pour prendre la différence de l'image pour une fausse détection lorsque le bouton est détecté.
La prochaine fois, j'aimerais le combiner avec la fonction d'enregistrement que j'ai créée la dernière fois. Eh bien
Recommended Posts