遥感图像匹配(高分4匹配Landsat8)-Python+Opencv/SIFT+GDAL

高分系列遥感影像的一个问题是难以进行精准的几何校正,通常是在专业软件(如ENVI)中处理,需要借助标准影像手动选择地面控制点来进行校正,操作比较复杂。本文的思路是借助Landsat8影像来进行关键点匹配,这样就能自动得到控制点。难点有:
①两种不同卫星的影像分辨率和细节方面差异较大,难以进行准确的匹配。为解决此问题,将分辨率较高的Landsat影像进行了均值滤波。
②遥感影像的存储格式不能直接用opencv处理,需要转换成8位整型灰度图,这里只用了一个全色波段。

# -*- coding: utf-8 -*-
# @File  : siftMatch.py
# @Author: Freezinghot
# @Date  : 2021/2/7
# @Desc  : SIFT图像配准
import cv2
import numpy as np
import gdal
from PIL import Image
from matplotlib import pyplot as plt


# SIFT特征检测
def sift_kp(image):
    #gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)    # 灰度图转换,如果是普通RGB图像需要这一行
    sift = cv2.xfeatures2d.SIFT_create()                    # 实例化sift
    kp, des = sift.detectAndCompute(image, None)            # 找出关键点并计算关键点对应的sift特征向量。
# kp 是一个关键点列表。des是一个numpy数组,其大小是关键的数目乘以128.image表示输入的灰度图
# kp_image = cv2.drawKeypoints(gray_image, kp, None)      # 在图中画出关键点(输入,关键点,输出)
    kp_image = cv2.drawKeypoints(image, kp, None)
    # print(kp, des)
    return kp_image, kp, des


def get_good_match(des1, des2):
    bf = cv2.BFMatcher()
    matches = bf.knnMatch(des1, des2, k=2)  # des1为模板图,des2为匹配图
    #matches = sorted(matches, key=lambda x: x[0].distance / x[1].distance)
    good = []
    for m, n in matches:
        if m.distance < 0.75 * n.distance:
            good.append(m)
    return good


def siftImageAlignment(img1, img2):
    _, kp1, des1 = sift_kp(img1)
    _, kp2, des2 = sift_kp(img2)
    goodMatch = get_good_match(des1, des2)
    if len(goodMatch) > 10:
        ptsA = np.float32([kp1[m.queryIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
        ptsB = np.float32([kp2[m.trainIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
        ransacReprojThreshold = 5
        H, status = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, ransacReprojThreshold)
        imgOut = cv2.warpPerspective(img2, H, (img1.shape[1], img1.shape[0]),
                                     flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
    else:
        print("goodMatches less than 10")

    return imgOut, H, status


def tiftoint8(min, max, imdata):
    scale = max-min
    out_img = ((imdata/scale)*256).astype(np.uint8)
    return out_img

inds2 = "E:\\RSDATA\\GFdata\\LC08_L1TP_120035_20200424_01_T1\\LC08_L1TP_120035_20200424_20200508_01_T1_B8_resized50.TIF"
inds1 = "E:\\RSDATA\\GFdata\\tempout\\GF4_PMI_E121.6_N37.1_20200424_L1A0000296007\\GF4_PMS_E121.6_N37.1_20200424_L1A0000296007_clip.tiff"
img1 = gdal.Open(inds1)	
img2 = gdal.Open(inds2)
im1_width = img1.RasterXSize  # 栅格矩阵的列数
im1_height = img1.RasterYSize  # 栅格矩阵的行数
im1_bands = img1.RasterCount  # 波段数
im1_geotrans = img1.GetGeoTransform() # 获取仿射矩阵信息
im1_proj = img1.GetProjection()   # 获取投影信息
im2_width = img2.RasterXSize  # 栅格矩阵的列数
im2_height = img2.RasterYSize  # 栅格矩阵的行数
im2_bands = img2.RasterCount  # 波段数

im_data1 = img1.ReadAsArray(0,0,im1_width,im1_height)#获取数据
max1 = im_data1.max()
min1 = im_data1.min()
in_img1uint8 = tiftoint8(min1, max1, im_data1)
im_data2 = img2.ReadAsArray(0,0,im2_width,im2_height)#获取数据
max2 = im_data2.max()
min2 = im_data2.min()
in_img2uint8 = tiftoint8(min2, max2, im_data2)
'''
# 平滑滤波
in_img1uint8 = cv2.blur(in_img1uint8[4],(3,5))#模板大小3*5
in_img2uint8 = cv2.blur(in_img2uint8,(3,5))
plt.subplot(1,2,1),plt.imshow(in_img1uint8,'gray')
plt.subplot(1,2,2),plt.imshow(in_img2uint8,'gray')
plt.show()
'''
in_img2uint8 = cv2.blur(in_img2uint8,(3,5))
# 执行sift
_, kp1, des1 = sift_kp(in_img1uint8[0])
_, kp2, des2 = sift_kp(in_img2uint8)
goodMatch = get_good_match(des1, des2)
print(goodMatch)
# 提取关键点中的坐标
src_pts = np.float32([kp1[m.queryIdx].pt for m in goodMatch]).reshape(-1,1,2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in goodMatch]).reshape(-1,1,2)
print(src_pts,dst_pts)
#H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 2.0)
#wrapimg = cv2.warpPerspective(in_img1uint8[0], H, (im1_width, im1_height))
wrapimg, H, status = siftImageAlignment(in_img1uint8[0], in_img2uint8)
# 显示匹配点和匹配结果
matchesMask = status.ravel().tolist()
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
        singlePointColor = None,
        matchesMask = matchesMask, # draw only inliers
        flags = 2)
img3 = cv2.drawMatches(in_img1uint8[0],kp1,in_img2uint8,kp2,goodMatch,None,**draw_params)
plt.imshow(img3,'gray')
plt.show()
# 写入新的tiff文件
datatype = gdal.GDT_UInt16
wrapimg = ((wrapimg*32767)//255).astype(np.uint16)
path = "E:\\RSDATA\\GFdata\\tempout\\LC8wrapimg.tif"
driver = gdal.GetDriverByName("GTiff")
dataset = driver.Create(path, im1_width, im1_height, 1, datatype,options=["INTERLEAVE=BAND"])
print("创建文件成功")
dataset.SetGeoTransform(im1_geotrans)  # 写入仿射变换参数
dataset.SetProjection(im1_proj)  # 写入投影
print("写入投影")
dataset.GetRasterBand(1).WriteArray(wrapimg)
del dataset

遥感图像匹配(高分4匹配Landsat8)-Python+Opencv/SIFT+GDAL_第1张图片

本来是计划用匹配点生成的转换矩阵直接对高分影像做一个变换,结果不理想,后面考虑将提取到的匹配点作为控制点,用gdal对原影像进行控制点校正。程序不完善,只是一个预研实验,在这里做个记录,供大家参考。

你可能感兴趣的:(opencv,gdal,python,sift算法)