修改像素精度

This commit is contained in:
2026-03-10 17:31:02 +08:00
parent 5e0984bf9c
commit c3bd750a66
4 changed files with 1804 additions and 47 deletions

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -61,9 +61,9 @@ logger = logging.getLogger(__name__)
# ---------- 配置 ----------
# 请根据实际情况修改这些路径
REF_TIF = r"E:\is2\guidingsahn\result.tif" # 参考 tif 文件路径
BIP_DIR = Path(r"E:\is2\guidingsahn") # .bip 文件所在文件夹
OUT_DIR = Path(r"E:\is2\guidingsahn\output") # 输出文件夹
REF_TIF = r"E:\is2\dingshanhu\mask_water.tif" # 参考 tif 文件路径
BIP_DIR = Path(r"E:\is2\dingshanhu") # .bip 文件所在文件夹
OUT_DIR = Path(r"E:\is2\dingshanhu\output") # 输出文件夹
# 匹配算法选择
MATCHER_NAME = "matchanything-roma" # 可选: xfeat-star, loftr, roma, superpoint-lightglue, sift-lightglue 等

View File

@ -61,7 +61,7 @@ logger = logging.getLogger(__name__)
# ---------- 配置 ----------
# 请根据实际情况修改这些路径
REF_TIF = r"E:\is2\guidingsahn\result.tif" # 参考 tif 文件路径
REF_TIF = r"E:\is2\guidingsahn\mask_water.tif" # 参考 tif 文件路径
BIP_DIR = Path(r"E:\is2\guidingsahn") # .bip 文件所在文件夹
OUT_DIR = Path(r"E:\is2\guidingsahn\output") # 输出文件夹
@ -157,7 +157,30 @@ def _expand_window(win, pad, max_w, max_h):
row_off = int(max(0, win.row_off - pad))
col_end = int(min(max_w, win.col_off + win.width + pad))
row_end = int(min(max_h, win.row_off + win.height + pad))
return rasterio.windows.Window(col_off, row_off, col_end - col_off, row_end - row_off)
return rasterio.windows.Window(col_off, row_off, col_end - col_off, col_end - col_off,)
def _pixel_size_xy(transform: Affine):
rx = float(np.hypot(transform.a, transform.d))
ry = float(np.hypot(transform.b, transform.e))
if not np.isfinite(rx) or rx <= 0:
rx = float(abs(transform.a)) if transform.a != 0 else 1.0
if not np.isfinite(ry) or ry <= 0:
ry = float(abs(transform.e)) if transform.e != 0 else 1.0
return rx, ry
def _grid_from_bounds(bounds, res_x: float, res_y: float):
left, bottom, right, top = [float(v) for v in bounds]
res_x = float(abs(res_x))
res_y = float(abs(res_y))
w = int(np.ceil((right - left) / max(1e-12, res_x)))
h = int(np.ceil((top - bottom) / max(1e-12, res_y)))
w = max(1, w)
h = max(1, h)
out_transform = Affine(res_x, 0.0, left, 0.0, -res_y, top)
return out_transform, w, h
def estimate_transform(method, k0, k1):
"""统一的变换估计函数,支持多种变换类型"""
@ -689,41 +712,43 @@ def process_bip_to_tif(bip_path: Path, ref_dataset, matcher, out_dir: Path, stat
return False
bbox_window = rasterio.windows.Window(min_x, min_y, bbox_w, bbox_h)
bbox_transform = ref_dataset.window_transform(bbox_window)
bounds = rasterio.windows.bounds(bbox_window, transform=ref_dataset.transform)
res_x, res_y = _pixel_size_xy(src.transform)
out_transform, out_w, out_h = _grid_from_bounds(bounds, res_x, res_y)
out_path = out_dir / f"{bip_path.stem}_registered.bip"
src_nodata = src.nodata
dst_nodata = src_nodata if src_nodata is not None else 0
out_profile = ref_dataset.profile.copy()
out_profile = src.profile.copy()
out_profile.update(
driver="ENVI",
dtype=src.dtypes[0],
height=bbox_h,
width=bbox_w,
height=out_h,
width=out_w,
count=src.count,
transform=bbox_transform,
transform=out_transform,
crs=ref_crs,
interleave="bip",
compress=None,
nodata=dst_nodata
)
# 重采样到最小外接矩形
with rasterio.open(out_path, "w", **out_profile) as out_ds:
for b in range(1, src.count + 1):
src_band = src.read(b).astype(np.float32)
dst_band = np.zeros((bbox_h, bbox_w), dtype=np.float32)
dst_band = np.zeros((out_h, out_w), dtype=np.float32)
reproject(
source=src_band,
destination=dst_band,
src_transform=corrected_affine,
src_crs=ref_crs,
dst_transform=bbox_transform,
dst_transform=out_transform,
dst_crs=ref_crs,
src_nodata=src_nodata,
dst_nodata=dst_nodata,
resampling=Resampling.bilinear,
resampling=Resampling.nearest,
)
if np.issubdtype(np.dtype(out_profile["dtype"]), np.integer):
@ -772,46 +797,56 @@ def process_bip_to_tif(bip_path: Path, ref_dataset, matcher, out_dir: Path, stat
logger.warning(f"单应变换最小外接矩形无效: {bip_path.name}")
return False
# 创建输出窗口
bbox_window = rasterio.windows.Window(min_x, min_y, bbox_w, bbox_h)
bbox_transform = ref_dataset.window_transform(bbox_window)
bounds = rasterio.windows.bounds(bbox_window, transform=ref_dataset.transform)
# 子窗口坐标的单应矩阵(输出坐标系是子窗口像素)
T_off = np.array([[1,0,min_x],[0,1,min_y],[0,0,1]], dtype=np.float64)
H_sub = np.linalg.inv(T_off) @ H_full
res_x, res_y = _pixel_size_xy(src.transform)
out_transform, out_w, out_h = _grid_from_bounds(bounds, res_x, res_y)
out_path = out_dir / f"{bip_path.stem}_registered.bip"
src_nodata = src.nodata
dst_nodata = src_nodata if src_nodata is not None else 0
out_profile = ref_dataset.profile.copy()
out_profile = src.profile.copy()
out_profile.update(
driver="ENVI",
dtype=src.dtypes[0],
height=bbox_h,
width=bbox_w,
height=out_h,
width=out_w,
count=src.count,
transform=bbox_transform,
transform=out_transform,
crs=ref_crs,
interleave="bip",
compress=None,
nodata=dst_nodata
)
# 使用 OpenCV 进行单应变换重采样
ref_transform = ref_dataset.transform
Rt = np.array(
[[ref_transform.a, ref_transform.b, ref_transform.c],
[ref_transform.d, ref_transform.e, ref_transform.f],
[0.0, 0.0, 1.0]],
dtype=np.float64,
)
Out = np.array(
[[out_transform.a, out_transform.b, out_transform.c],
[out_transform.d, out_transform.e, out_transform.f],
[0.0, 0.0, 1.0]],
dtype=np.float64,
)
M = np.linalg.inv(Out) @ Rt @ H_full.astype(np.float64)
with rasterio.open(out_path, "w", **out_profile) as out_ds:
for b in range(1, src.count + 1):
src_band = src.read(b).astype(np.float32)
dst_band = np.full((bbox_h, bbox_w), dst_nodata, dtype=np.float32)
# 使用 OpenCV warpPerspective子窗口坐标
dst_band = cv2.warpPerspective(
src_band, H_sub,
(bbox_w, bbox_h),
flags=cv2.INTER_LINEAR,
src_band,
M,
(out_w, out_h),
flags=cv2.INTER_NEAREST,
borderMode=cv2.BORDER_CONSTANT,
borderValue=dst_nodata
)
borderValue=float(dst_nodata)
).astype(np.float32)
# 转回目标 dtype
if np.issubdtype(np.dtype(out_profile["dtype"]), np.integer):
@ -957,7 +992,8 @@ def process_bip_to_tif(bip_path: Path, ref_dataset, matcher, out_dir: Path, stat
output_shape=(bbox_h, bbox_w),
mode='constant',
cval=dst_nodata,
preserve_range=True
preserve_range=True,
order=0
).astype(np.float32)
# 转回目标 dtype
@ -1060,7 +1096,8 @@ def process_bip_to_tif(bip_path: Path, ref_dataset, matcher, out_dir: Path, stat
output_shape=(bbox_h, bbox_w),
mode='constant',
cval=dst_nodata,
preserve_range=True
preserve_range=True,
order=0
).astype(np.float32)
if np.issubdtype(np.dtype(out_profile["dtype"]), np.integer):
@ -1091,7 +1128,7 @@ def process_bip_to_tif(bip_path: Path, ref_dataset, matcher, out_dir: Path, stat
# 使用OpenCV的remap进行重采样
dst_band = cv2.remap(
src_band, map_x, map_y,
interpolation=cv2.INTER_LINEAR,
interpolation=cv2.INTER_NEAREST,
borderMode=cv2.BORDER_CONSTANT,
borderValue=dst_nodata
)
@ -1192,44 +1229,44 @@ def process_bip_to_tif(bip_path: Path, ref_dataset, matcher, out_dir: Path, stat
logger.warning(f"最小外接矩形无效: {bip_path.name}")
return False
# 创建裁剪窗口和变换
bbox_window = rasterio.windows.Window(min_x, min_y, bbox_w, bbox_h)
bbox_transform = ref_dataset.window_transform(bbox_window)
bounds = rasterio.windows.bounds(bbox_window, transform=ref_dataset.transform)
res_x, res_y = _pixel_size_xy(src.transform)
out_transform, out_w, out_h = _grid_from_bounds(bounds, res_x, res_y)
out_path = out_dir / f"{bip_path.stem}_registered.bip"
src_nodata = src.nodata
dst_nodata = src_nodata if src_nodata is not None else 0
# 更新输出 profile 使用最小外接矩形
out_profile = ref_dataset.profile.copy()
out_profile = src.profile.copy()
out_profile.update(
driver="ENVI",
dtype=src.dtypes[0],
height=bbox_h,
width=bbox_w,
height=out_h,
width=out_w,
count=src.count,
transform=bbox_transform, # 使用最小外接矩形的变换
transform=out_transform,
crs=ref_crs,
interleave="bip",
compress=None,
nodata=dst_nodata
)
# 重采样到最小外接矩形
with rasterio.open(out_path, "w", **out_profile) as out_ds:
for b in range(1, src.count + 1):
src_band = src.read(b).astype(np.float32)
dst_band = np.zeros((bbox_h, bbox_w), dtype=np.float32)
dst_band = np.zeros((out_h, out_w), dtype=np.float32)
reproject(
source=src_band,
destination=dst_band,
src_transform=corrected_affine,
src_crs=ref_crs,
dst_transform=bbox_transform,
dst_transform=out_transform,
dst_crs=ref_crs,
src_nodata=src_nodata,
dst_nodata=dst_nodata,
resampling=Resampling.bilinear,
resampling=Resampling.nearest,
)
# 转回目标 dtype
if np.issubdtype(np.dtype(out_profile["dtype"]), np.integer):

1714
test V9GUI.py Normal file

File diff suppressed because it is too large Load Diff