Избранная проблема с выравниванием изображений - PullRequest
0 голосов
/ 09 января 2020

Я пытаюсь изучить OpenCV, чтобы улучшить сценарий, который я написал для сравнения технических чертежей. Я использую код (см. Ниже), найденный в этом учебном пособии, но у меня нулевой успех с ним. В учебнике автор использует пример бланка для эталонного изображения и фотографии в завершенном виде в качестве изображения для выравнивания. Моя ситуация очень похожа, потому что я пытаюсь использовать пустой рисунок надписи, как мой опорного изображения и отсканированное изображение чертежа, как мое изображение, чтобы выровнять.

1004 * Моя цель состоит в том, чтобы использовать OpenCV, чтобы очистить отсканированный инженерные чертежи, чтобы они были выровнены правильно, но независимо от того, что я пробую в параметрах MAX_FEATURES и GOOD_MATCH_PERCENT, я получаю изображение, которое выглядит как всплеск черно-белой звезды. Кроме того, когда я просматриваю файл «match.jpg», сгенерированный сценарием, кажется, что нет правильных совпадений. Я пробовал несколько рисунков и получаю одинаковые результаты.

Может кто-нибудь увидеть причину, по которой этот скрипт не будет работать так, как я пытаюсь его использовать?

from __future__ import print_function
import cv2
import numpy as np


MAX_FEATURES = 500
GOOD_MATCH_PERCENT = 0.15


def alignImages(im1, im2):

  # Convert images to grayscale
  im1Gray = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
  im2Gray = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY)

  # Detect ORB features and compute descriptors.
  orb = cv2.ORB_create(MAX_FEATURES)
  keypoints1, descriptors1 = orb.detectAndCompute(im1Gray, None)
  keypoints2, descriptors2 = orb.detectAndCompute(im2Gray, None)

  # Match features.
  matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING)
  matches = matcher.match(descriptors1, descriptors2, None)

  # Sort matches by score
  matches.sort(key=lambda x: x.distance, reverse=False)

  # Remove not so good matches
  numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
  matches = matches[:numGoodMatches]

  # Draw top matches
  imMatches = cv2.drawMatches(im1, keypoints1, im2, keypoints2, matches, None)
  cv2.imwrite("matches.jpg", imMatches)

  # Extract location of good matches
  points1 = np.zeros((len(matches), 2), dtype=np.float32)
  points2 = np.zeros((len(matches), 2), dtype=np.float32)

  for i, match in enumerate(matches):
    points1[i, :] = keypoints1[match.queryIdx].pt
    points2[i, :] = keypoints2[match.trainIdx].pt

  # Find homography
  h, mask = cv2.findHomography(points1, points2, cv2.RANSAC)

  # Use homography
  height, width, channels = im2.shape
  im1Reg = cv2.warpPerspective(im1, h, (width, height))

  return im1Reg, h


if __name__ == '__main__':

  # Read reference image
  refFilename = "form.jpg"
  print("Reading reference image : ", refFilename)
  imReference = cv2.imread(refFilename, cv2.IMREAD_COLOR)

  # Read image to be aligned
  imFilename = "scanned-form.jpg"
  print("Reading image to align : ", imFilename);  
  im = cv2.imread(imFilename, cv2.IMREAD_COLOR)

  print("Aligning images ...")
  # Registered image will be resotred in imReg. 
  # The estimated homography will be stored in h. 
  imReg, h = alignImages(im, imReference)

  # Write aligned image to disk. 
  outFilename = "aligned.jpg"
  print("Saving aligned image : ", outFilename); 
  cv2.imwrite(outFilename, imReg)

  # Print estimated homography
  print("Estimated homography : \n",  h)

Шаблон изображения : template

Изображение для выравнивания: scanned drawing

Ожидаемый результат Image: enter image description here

Ответы [ 2 ]

1 голос
/ 09 января 2020

Вот один способ в Python / OpenCV, использующий жесткое аффинное преобразование (только масштаб, поворот и перевод - без перекоса или перспективы), чтобы деформировать одно изображение в соответствии с другим. Он использует findTransformE CC () - усиление максимизации коэффициента корреляции) - чтобы получить матрицу вращения, а затем использует warpAffine для жесткого деформирования.

Шаблон:

enter image description here

Изображение, которое будет деформировано:

enter image description here

import cv2
import numpy as np
import math
import sys

# Get the image files from the command line arguments
# These are full paths to the images
# image2 will be warped to match image1
# argv[0] is name of script
image1 = sys.argv[1]
image2 = sys.argv[2]
outfile = sys.argv[3]

# Read the images to be aligned
# im2 is to be warped to match im1
im1 =  cv2.imread(image1);
im2 =  cv2.imread(image2);

# Convert images to grayscale for computing the rotation via ECC method
im1_gray = cv2.cvtColor(im1,cv2.COLOR_BGR2GRAY)
im2_gray = cv2.cvtColor(im2,cv2.COLOR_BGR2GRAY)

# Find size of image1
sz = im1.shape

# Define the motion model - euclidean is rigid (SRT)
warp_mode = cv2.MOTION_EUCLIDEAN

# Define 2x3 matrix and initialize the matrix to identity matrix I (eye)
warp_matrix = np.eye(2, 3, dtype=np.float32)

# Specify the number of iterations.
number_of_iterations = 5000;

# Specify the threshold of the increment
# in the correlation coefficient between two iterations
termination_eps = 1e-3;

# Define termination criteria
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, number_of_iterations,  termination_eps)

# Run the ECC algorithm. The results are stored in warp_matrix.
(cc, warp_matrix) = cv2.findTransformECC (im1_gray, im2_gray, warp_matrix, warp_mode, criteria, None, 1)

# Warp im2 using affine
im2_aligned = cv2.warpAffine(im2, warp_matrix, (sz[1],sz[0]), flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP);

# write output
cv2.imwrite(outfile, im2_aligned)

# Print rotation angle
row1_col0 = warp_matrix[0,1]
angle = math.degrees(math.asin(row1_col0))
print(angle)

Результат:

enter image description here

Результирующий угол поворота (в градусах):

-0.3102187026194794


Обратите внимание, что при желании вы можете изменить цвет фона в affineWarp на белый.

Также сделайте эпсилон завершения меньшим на порядок или два для большей точности, но более продолжительного времени обработки.

Другой жесткий аффинный подход, о котором я упоминал ранее в моих комментариях, , чтобы использовать сопоставление объектов ORB, отфильтровать ключевые точки, а затем с помощью метода valuesAffinePartial2D () получить жесткую аффинную матрицу. Затем используйте это, чтобы деформировать изображение. Для больших углов это кажется мне более надежным, чем метод E CC. Но метод E CC кажется более точным для небольших вращений.

import cv2
import numpy as np
import math
import sys


MAX_FEATURES = 10000
GOOD_MATCH_PERCENT = 0.15
DIFFY_THRESH = 2

# Get the image files from the command line arguments
# These are full paths to the images
# image[2] will be warped to match image[1]
# argv[0] is name of script
file1 = sys.argv[1]
file2 = sys.argv[2]
outFile = sys.argv[3]

# Read image1
image1 = cv2.imread(file1, cv2.IMREAD_COLOR)

# Read image2 to be warped to match image1
image2 = cv2.imread(file2, cv2.IMREAD_COLOR)

# Convert images to grayscale
image1Gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
image2Gray = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)

# Detect ORB features and compute descriptors.
orb = cv2.ORB_create(MAX_FEATURES)
keypoints1, descriptors1 = orb.detectAndCompute(image1Gray, None)
keypoints2, descriptors2 = orb.detectAndCompute(image2Gray, None)

# Match features.
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = matcher.match(descriptors1, descriptors2, None)

# Sort matches by score
matches.sort(key=lambda x: x.distance, reverse=False)

# Remove not so good matches
numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
matches = matches[:numGoodMatches]
#print('numgood',numGoodMatches)

# Extract location of good matches and filter by diffy if rotation is small
points1 = np.zeros((len(matches), 2), dtype=np.float32)
points2 = np.zeros((len(matches), 2), dtype=np.float32)

for i, match in enumerate(matches):
    points1[i, :] = keypoints1[match.queryIdx].pt
    points2[i, :] = keypoints2[match.trainIdx].pt

# initialize empty arrays for newpoints1 and newpoints2 and mask
newpoints1 = np.empty(shape=[0, 2], dtype=np.float32)
newpoints2 = np.empty(shape=[0, 2], dtype=np.float32)
matches_Mask = [0] * len(matches)

count=0
for i in range(len(matches)):
    pt1 = points1[i]
    pt2 = points2[i]
    pt1x, pt1y = zip(*[pt1])
    pt2x, pt2y = zip(*[pt2])
    diffy = np.float32( np.float32(pt2y) - np.float32(pt1y) )
    if abs(diffy) < DIFFY_THRESH:
        newpoints1 = np.append(newpoints1, [pt1], axis=0).astype(np.uint8)
        newpoints2 = np.append(newpoints2, [pt2], axis=0).astype(np.uint8)
        matches_Mask[i]=1
        count += 1

# Find Affine Transformation
# note swap of order of newpoints here so that image2 is warped to match image1
m, inliers = cv2.estimateAffinePartial2D(newpoints2,newpoints1)

# Use affine transform to warp im2 to match im1
height, width, channels = image1.shape
image2Reg = cv2.warpAffine(image2, m, (width, height))

# Write aligned image to disk. 
cv2.imwrite(outFile, image2Reg)

# Print angle
row1_col0 = m[1,0]
print('row1_col0:',row1_col0)
angle = math.degrees(math.asin(row1_col0))
print('angle', angle)


Результат Изображение:

enter image description here

Результат Угол поворота:

-0.6123936361765413


0 голосов
/ 10 января 2020

После некоторых проб и ошибок я решил, что мне не нужно искать гомографию, чтобы правильно выровнять мои изображения. Поскольку мои изображения нужно лишь слегка масштабировать и поворачивать, мой лучший вариант - найти самые внешние точки блока заголовка чертежа и выровнять одно изображение с другим с помощью преобразования.

Мой подход заключается в использовании Функция поиска углов Харриса позволяет найти все углы на чертеже, а затем выполнить простой расчет, чтобы найти точки, которые находятся на кратчайшем расстоянии от углов холста чертежа (это внешние углы блока заголовка чертежа). Затем я беру 3 из точек (вверху слева, вверху справа и внизу слева) и использую преобразование для масштабирования / поворота одного рисунка к другому.

Ниже приведен код, который я использовал:

import cv2
import numpy as np
import math

img1 = cv2.imread('reference.jpg')
img2 = cv2.imread('to-be-aligned.jpg')

#Find the corner points of img1
h1,w1,c=img1.shape
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray1 = np.float32(gray1)
dst1 = cv2.cornerHarris(gray1,5,3,0.04)
ret1, dst1 = cv2.threshold(dst1,0.1*dst1.max(),255,0)
dst1 = np.uint8(dst1)
ret1, labels1, stats1, centroids1 = cv2.connectedComponentsWithStats(dst1)
criteria1 = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners1 = cv2.cornerSubPix(gray1,np.float32(centroids1),(5,5),(-1,-1),criteria1)

#Find the corner points of img2
h2,w2,c=img2.shape
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
gray2 = np.float32(gray2)
dst2 = cv2.cornerHarris(gray2,5,3,0.04)
ret2, dst2 = cv2.threshold(dst2,0.1*dst2.max(),255,0)
dst2 = np.uint8(dst2)
ret2, labels2, stats2, centroids2 = cv2.connectedComponentsWithStats(dst2)
criteria2 = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners2 = cv2.cornerSubPix(gray2,np.float32(centroids2),(5,5),(-1,-1),criteria2)


#Find the top left, top right, and bottom left outer corners of the drawing frame for img1
a1=[0,0]
b1=[w1,0]
c1=[0,h1]
a1_dist=[]
b1_dist=[]
c1_dist=[]
for i in corners1:
    temp_a1=math.sqrt((i[0]-a1[0])**2+(i[1]-a1[1])**2)
    temp_b1=math.sqrt((i[0]-b1[0])**2+(i[1]-b1[1])**2)
    temp_c1=math.sqrt((i[0]-c1[0])**2+(i[1]-c1[1])**2)
    a1_dist.append(temp_a1)
    b1_dist.append(temp_b1)
    c1_dist.append(temp_c1)

print("Image #1 (reference):")
print("Top Left:")
print(corners1[a1_dist.index(min(a1_dist))])
print("Top Right:")
print(corners1[b1_dist.index(min(b1_dist))])
print("Bottom Left:")
print(corners1[c1_dist.index(min(c1_dist))])

#Find the top left, top right, and bottom left outer corners of the drawing frame for img2
a2=[0,0]
b2=[w2,0]
c2=[0,h2]
a2_dist=[]
b2_dist=[]
c2_dist=[]
for i in corners2:
    temp_a2=math.sqrt((i[0]-a2[0])**2+(i[1]-a2[1])**2)
    temp_b2=math.sqrt((i[0]-b2[0])**2+(i[1]-b2[1])**2)
    temp_c2=math.sqrt((i[0]-c2[0])**2+(i[1]-c2[1])**2)
    a2_dist.append(temp_a2)
    b2_dist.append(temp_b2)
    c2_dist.append(temp_c2)

print("Image #2 (image to align):")
print("Top Left:")
print(corners2[a2_dist.index(min(a2_dist))])
print("Top Right:")
print(corners2[b2_dist.index(min(b2_dist))])
print("Bottom Left:")
print(corners2[c2_dist.index(min(c2_dist))])

#Create the points for img1
point1 = np.zeros((3,2), dtype=np.float32)
point1[0][0]=corners1[a1_dist.index(min(a1_dist))][0]
point1[0][1]=corners1[a1_dist.index(min(a1_dist))][1]
point1[1][0]=corners1[b1_dist.index(min(b1_dist))][0]
point1[1][1]=corners1[b1_dist.index(min(b1_dist))][1]
point1[2][0]=corners1[c1_dist.index(min(c1_dist))][0]
point1[2][1]=corners1[c1_dist.index(min(c1_dist))][1]

#Create the points for img2
point2 = np.zeros((3,2), dtype=np.float32)
point2[0][0]=corners2[a2_dist.index(min(a2_dist))][0]
point2[0][1]=corners2[a2_dist.index(min(a2_dist))][1]
point2[1][0]=corners2[b2_dist.index(min(b2_dist))][0]
point2[1][1]=corners2[b2_dist.index(min(b2_dist))][1]
point2[2][0]=corners2[c2_dist.index(min(c2_dist))][0]
point2[2][1]=corners2[c2_dist.index(min(c2_dist))][1]

#Make sure points look ok:
print(point1)
print(point2)

#Transform the image
m = cv2.getAffineTransform(point2,point1)
image2Reg = cv2.warpAffine(img2, m, (w1, h1), borderValue=(255,255,255))

#Highlight found points in red:
img1[dst1>0.1*dst1.max()]=[0,0,255]
img2[dst2>0.1*dst2.max()]=[0,0,255]

#Output the images:
cv2.imwrite("output-img1-harris.jpg", img1)
cv2.imwrite("output-img2-harris.jpg", img2)
cv2.imwrite("output-harris-transform.jpg",image2Reg)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...