[Code] Calculate the offset of two pictures

need

The image at the same preset position will deviate in different time periods, so it is necessary to calculate the deviation value to correct the deviation.
Picture 1
base.jpg
insert image description here
shift.jpg

method one

Idea: Use cv2.phaseCorrelate(src1,src2)

import os.path

import cv2
import numpy as np
import time
base_path = "/home/data/wangchunyue/code/offset/jpg3/22/"
src1_path = os.path.join(base_path, "base.png")
src2_path = os.path.join(base_path, "shift.jpg")
src1 = cv2.imread(src1_path)
src2 = cv2.imread(src2_path)
src1 = src1[100:src1.shape[0]-100,0:src1.shape[1]]
src2 = src2[100:src2.shape[0]-100,0:src2.shape[1]]
add_img = cv2.addWeighted(src1, 0.5, src2, 0.5, 1)  # 图像融合,方便显示

src1 = np.float32(src1)
src2 = np.float32(src2)
src1 = cv2.cvtColor(src1, cv2.COLOR_BGR2GRAY)
src2 = cv2.cvtColor(src2, cv2.COLOR_BGR2GRAY)

# 函数说明:利用傅里叶变化,在频域进行相位匹配从而计算两张图片的平移量
start_time = time.time()
dst = cv2.phaseCorrelate(src1,src2)
end_time =time.time()
print("offsetv1 = {:.4f}s".format(end_time-start_time))
cv2.putText(add_img,str(dst[0]),(100,100),cv2.FONT_HERSHEY_COMPLEX,1, (0,255,0), 3)
cv2.imwrite(base_path + "\\" + "{}.jpg".format(src1_path.split("\\")[-1][:-4] +"+"+ src2_path.split("\\")[-1][:-4]), add_img)
print(dst[0])

Method Two

Idea: Use cv2.SIFT_create() to find the similarities between the two images, and then use the KDTree algorithm to find most of the points with the closest coordinate difference, which is the offset of the final two images.

import cv2
import numpy as np
import glob
import os
from tqdm import tqdm
import shutil
from sklearn.neighbors import KDTree
import time


def BFMatchV2(img1, img2):
    # 函数说明:sift算法用于识别两张图的相似点
    # 输入参数:一张底图,一张检测图,并且经过裁剪操作
    # 输出参数:所有的坐标差值
    # sift = cv2.xfeatures2d.SIFT_create()
    sift = cv2.SIFT_create()
    keypoints_1, descriptors_1 = sift.detectAndCompute(img1, None)
    keypoints_2, descriptors_2 = sift.detectAndCompute(img2, None)
    bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
    matches = bf.match(descriptors_1, descriptors_2)
    matches = sorted(matches, key=lambda x: x.distance)
    print(len(matches))
    img3 = cv2.drawMatches(img1, keypoints_1, img2, keypoints_2, matches[:10], img2, flags=2)
    #cv2.imwrite(result_path + "/" + "line.jpg", img3)
    Result = []
    for match in matches[:2000]:
        p1 = keypoints_1[match.queryIdx].pt
        p2 = keypoints_2[match.trainIdx].pt
        result = list(p2)[0] - list(p1)[0], list(p2)[1] - list(p1)[1]
        Result.append(result)
    return Result


def KDTreeQuery(Result):  
    # 函数说明:KDTree是一种聚类算法,用于计算坐标差值最接近的大多数点
    # 输入参数:所有的坐标差值
    # 输出参数:坐标差值最接近的大多数点中的第一个元素
    tree = KDTree(Result)
    all_nn_indices = tree.query_radius(Result, r=1.5)
    all_nns = [[Result[idx] for idx in nn_indices] for nn_indices in all_nn_indices]
    dic = dict()
    for nns in all_nns:
        dic[len(nns)] = nns
    result = dic[max(dic.keys())][0]
    return result


def SegImage(src1, src2):
    # 函数说明:用于将图片切分为上下两部分,并利用BFMatch函数,计算上下部分的所有的坐标差值
    # 输入参数:一张底图,一张检测图,没有经过裁剪操作
    # 输出参数:所有的坐标差值
    idx = [[130, 540, 0, 0], [540, 130, 0, 0]]
    add_result = []
    for i in range(2):
        print(idx[i][0], src1.shape[0] - idx[i][1], idx[i][2], src1.shape[1] - idx[i][3])
        dst1 = src1[idx[i][0]:src1.shape[0] - idx[i][1], idx[i][2]:src1.shape[1] - idx[i][3]]
        dst2 = src2[idx[i][0]:src2.shape[0] - idx[i][1], idx[i][2]:src2.shape[1] - idx[i][3]]
        result = BFMatchV2(dst1, dst2)
        print(dst1.shape,dst2.shape)
        add_result.extend(result)
    return add_result


if __name__ == "__main__":
    # 用于批量读取base_dir文件夹中的所有子文件数据,底图需要重命名为base,后缀名不做要求
    base_dir = "/data1/test/pianyi_v2/hntest/"
    paths = glob.glob(base_dir + "/*/" + 'base*')
    vesion = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
    file_name = base_dir.split("/")[-2]
    results_path = os.path.join(base_dir, '..', "_{}_result_{}".format(file_name, vesion))
    # 将原图和检测图拷贝到新的文件夹,用于对比数据
    for path in tqdm(paths):
        base_path = os.path.dirname(path)
        result_path = results_path + "/" + base_path.split("/")[-1]
        if not os.path.exists(result_path):
            shutil.copytree(base_path, result_path)
    # 开始计算底图和检测图的偏移量
    for path in tqdm(paths):
        root_path = os.path.dirname(path)
        result_path = results_path + "/" + root_path.split("/")[-1]
        src1_path = path
        files = os.listdir(root_path)
        for file in files:
            src1 = cv2.imdecode(np.fromfile(src1_path, dtype=np.uint8), 1)
            src1 = src1.copy()
            if "base" not in file:
                src2_path = root_path + "/" + file
                src2 = cv2.imdecode(np.fromfile(src2_path, dtype=np.uint8), 1)
                dst1 = src2.copy()
                rows, cols = dst1.shape[0], dst1.shape[1]
                add_img = cv2.addWeighted(src1, 0.5, src2, 0.5, 1)
                add_result = SegImage(src1, src2)
                print(len(add_result))
                result =KDTreeQuery(add_result)
                pic_name = file[:-4]
                MAT = np.float32([[1, 0, -result[0]], [0, 1, -result[1]]])
                dst2 = cv2.warpAffine(dst1, MAT, (cols, rows), borderValue=(255, 255, 255))
                cv2.putText(dst2, str(result), (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 3)
                cv2.imencode('.jpg', dst2)[1].tofile(result_path + "/" + "correct_{}.jpg".format(pic_name))

Result after correction

insert image description here

Guess you like

Origin blog.csdn.net/weixin_42326479/article/details/127747602