[Python] Combinez automatiquement et de manière transparente les images recadrées

Chose que tu veux faire

Les deux images recadrées sont ** automatiquement ** combinées pour que les coutures soient naturelles. 画像結合_イメージ_re.jpg

idée

En partant des bords des images supérieure et inférieure, la zone est progressivement rétrécie et comparée. La zone avec le degré de correspondance le plus élevé est combinée en tant que zone commune. 画像結合_アルゴイメージ_re.jpg

supposition

--Lire au format oreiller

Flow (ce que j'ai étudié)

    1. Rognage d'image
  1. Comparer des images
    1. Concaténer les images
  2. Pour réduire la quantité de calcul

1. 1. Rognage d'image

Cette fois, j'ai utilisé ʻImage.crop () `pour couper le format de l'oreiller.

Image.crop((Coordonnée X de l'extrémité gauche du découpage,Coordonnée y supérieure,Coordonnée x la plus à droite,Coordonnée y inférieure))

Notez que l'argument doit être spécifié sous forme de taple et que les ** parenthèses "(" ")" sont dupliquées **. Afin de réduire autant que possible la quantité de calcul, le plus petit du côté supérieur et du côté inférieur est défini comme zone de départ de la comparaison, et il est réduit de 1px. (Dans l'exemple de code, si l'image du haut est grande, la différence de hauteur est stockée dans la variable dif_h et utilisée pour spécifier les coordonnées supérieures de rognage.)

2. Comparer des images

L'image recadrée est convertie au format opencv et les images sont comparées en utilisant cv2.matchTemplate ().

cv2.matchTemplate(Image à comparer 1,Image 2 à comparer,Mode de correspondance)

Il semble y avoir différents modes de correspondance, mais je pense que tout est OK (à quelques exceptions près) pour cette application, j'ai donc utilisé le standard de type cv2.TM_CCOEFF_NORMED. Puisque la sortie de matchTemplate est une image en échelle de gris (probablement) qui montre le degré de correspondance dans la lumière et l'obscurité, la valeur maximale = le résultat de l'évaluation correspondante de cette image est obtenue en utilisant cv2.minMaxLoc ().

cv2.minMaxLoc(Image en échelle de gris à évaluer)[1]

Comme pour la valeur de retour de minmaxLoc, la valeur maximale est stockée dans la seconde, donc la valeur maximale est retirée avec [1]. (Vous trouverez des détails sur la correspondance des modèles d'image sur cette page Est expliqué dans)

Répétez ce qui précède avec une instruction for tout en modifiant la zone pour trouver l'endroit où le résultat d'évaluation correspondant est maximisé.

3. 3. Concaténer les images

J'ai cité cette page. https://note.nkmk.me/python-pillow-concat-images/

def get_concat_v(im1, im2):
    dst = Image.new('RGB', (im1.width, im1.height + im2.height))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (0, im1.height))
    return dst

Dans l'image au format oreiller, créez une zone avec ʻImage.new () et collez l'image à connecter avec ʻImage.paste ().

4. Pour réduire la quantité de calcul

Comme vous pouvez le voir en l'essayant, ** Plus la taille de l'image est grande, plus cela prend du temps **. Cette fois, elle est en niveaux de gris, et la plus petite de l'image supérieure et de l'image inférieure est définie comme taille de la zone de départ de comparaison. Bien que non adopté cette fois, je pense que la quantité de calcul peut être réduite en redimensionnant et en comparant les images, en limitant la zone à comparer et en mettant fin à la comparaison lorsqu'une certaine valeur d'évaluation est dépassée.

Code complété

import numpy as np
from PIL import Image
import cv2

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
def auto_img_concat_v(upper_img, under_img):

    max_res_num = 0  #Enregistrer la valeur maximale du résultat d'évaluation correspondant
    over_pixel = 0  #Enregistrez le nombre de pixels qui se chevauchent à l'évaluation de correspondance maximale

    img_w = upper_img.width
    upper_h = upper_img.height
    under_h = under_img.height

    compare_height = min(upper_h, under_h)  #Nombre de pixels à comparer (hauteur)

    #Si la hauteur de l'image ci-dessus est élevée, obtenez la différence (sinon 0)
    dif_h = (upper_h - under_h) if upper_h > under_h else 0

    for i in range(1, compare_height):

        search_img = upper_img.crop((0, i + dif_h, img_w, upper_h))  #Découper l'image ci-dessus
        target_img = under_img.crop((0, 0, img_w, compare_height - i))  #Découper l'image ci-dessous

        search_np = np.array(search_img, dtype=np.uint8)  #Convertir l'image en tableau (image du haut)
        cv_search_img = cv2.cvtColor(search_np, cv2.COLOR_RGB2GRAY)  #Échelle de gris (image du haut)

        target_np = np.array(target_img, dtype=np.uint8)  #〃 (ci-dessous l'image)
        cv_target_img = cv2.cvtColor(target_np, cv2.COLOR_RGB2GRAY)  #〃 (ci-dessous l'image)

        res = cv2.matchTemplate(
            cv_search_img, cv_target_img, cv2.TM_CCOEFF_NORMED)  #Évaluation de correspondance (la sortie est une image en échelle de gris montrant une similitude)
        res_num = cv2.minMaxLoc(res)[1]  #Obtenez une évaluation correspondante numériquement
        print(res_num, "\n", i)

        if max_res_num < res_num:  #Obtenez la valeur maximale du résultat d'évaluation correspondant
            max_res_num = res_num
            over_pixel = target_img.height  #Obtenez le nombre de pixels qui se chevauchent à la valeur d'évaluation correspondante maximale

    print("\n", max_res_num, "\n", over_pixel)

    if max_res_num > 0.98:  #Si la valeur d'évaluation est supérieure à un certain niveau, joindre le traitement
        result_img = get_concat_v(upper_img.crop(
            (0, 0, img_w, upper_h - over_pixel)), under_img)  #Combinaison d'images
        return result_img
    else:
        print("La combinaison d'images a échoué")
        
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
#Fonction de concaténation d'images (direction verticale)
def get_concat_v(im1, im2):
    dst = Image.new('RGB', (im1.width, im1.height + im2.height))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (0, im1.height))
    return dst

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
if __name__ == "__main__":
    upper = Image.open(r"C:\Users\aaa\Desktop\Danbo_upper.jpg ")
    under = Image.open(r"C:\Users\aaa\Desktop\Danbo_under.jpg ")
    concat_img = auto_img_concat_v(upper, under)

    if concat_img:
        concat_img.show()

résultat

結果re.jpg J'ai pu bien combiner.

Plans futurs

Il existe des problèmes tels qu'une grande quantité de calculs et une incompatibilité avec des images qui ne correspondent pas dans le sens horizontal. J'ai pu faire ce que je voulais faire pour le moment. À l'avenir, j'aimerais créer un outil qui connecte automatiquement les écrans défilés en combinaison avec pyautog.

Recommended Posts

[Python] Combinez automatiquement et de manière transparente les images recadrées
Capturer des images avec Pupil, python et OpenCV
Générez automatiquement des images de koala et d'ours
Importer et exporter des images GeoTiff avec Python
Rechercher et télécharger automatiquement des vidéos YouTube avec Python
Créez automatiquement des rapports Word et Excel avec Python
Divisez les images Python et disposez-les côte à côte
Collez automatiquement des images dans des matériaux Powerpo avec python + α
Traduisez automatiquement DeepL en anglais avec Python et Selenium
[python] Compresser et décompresser
Astuces Python et Numpy
[Python] pip et roue
Itérateur et générateur Python
Paquets et modules Python
Intégration Vue-Cli et Python
Exécuter automatiquement le fichier python
Ruby, Python et carte
entrée et sortie python
Python et Ruby se séparent
Python asyncio et ContextVar
J'ai essayé de [gratter] des images de mode et des phrases de texte avec Python.
[Introduction à Python] Combinaison des données Nikkei Average et NY Dow CSV
Comment se connecter à AtCoder avec Python et soumettre automatiquement
Notes sur la lecture et l'écriture d'images TIFF float32 avec python