基于SIFT和小波变换的图像拼接融合算法的设计与实现图像融合拼接GUI设计包括图像融合和图像拼接的Matlab实现上周去逛滨江公园拍了两张湖景照本来想拼个全景发朋友圈结果手动拖来拖去要么错位要么中间一条亮瞎眼的拼接缝折腾半小时还是翻车了。后来翻到之前攒的SIFT加小波变换的拼接代码改吧改吧终于搞出能用的东西今天跟大伙唠唠这个接地气的图像拼接工具。基于SIFT和小波变换的图像拼接融合算法的设计与实现图像融合拼接GUI设计包括图像融合和图像拼接的Matlab实现整个流程其实挺顺的先找两张图的共同特征点对齐再用小波变换把拼接缝磨平最后整个傻瓜式GUI不用敲命令行也能跑。第一步先把两张图的特征点对上首先得让两张图对齐不然拼出来就是两张歪歪扭扭的贴纸糊在一起。这里用SIFT找特征点不用自己手写算法新版Matlab自带的工具就够用省得调半天参数% 读入两张待拼接的图记得换成你自己的图片路径 img1 imread(park_left.jpg); img2 imread(park_right.jpg); % SIFT对灰度图更友好先转成单通道 gray1 rgb2gray(img1); gray2 rgb2gray(img2); % 提取特征点和对应的描述子 points1 detectSIFTFeatures(gray1); [features1, valid_pt1] extractFeatures(gray1, points1); points2 detectSIFTFeatures(gray2); [features2, valid_pt2] extractFeatures(gray2, points2); % 暴力匹配特征加个阈值过滤掉不靠谱的配对 match_pairs matchFeatures(features1, features2, MatchThreshold, 5); matched_pt1 valid_pt1(match_pairs(:,1),:); matched_pt2 valid_pt2(match_pairs(:,2),:);这里踩过坑一开始把MatchThreshold设成10结果匹配了一堆歪瓜裂枣的错配对拼出来的图直接歪到姥姥家改成5之后就清爽多了留下来的都是靠谱的对应点。第二步算出两张图的变换关系找到匹配点之后用单应矩阵把两张图掰到同一个坐标系里还要用RANSAC筛掉剩下的错配对不然还是会歪% 估计单应矩阵RANSAC自动过滤错配 [tform, inlier_idx] estimateGeometricTransform(matched_pt2, matched_pt1, projective); % 把第二张图变换到第一张图的视角下 [rows1, cols1, ~] size(img1); [rows2, cols2, ~] size(img2); % 得手动算好总画布尺寸不然会裁掉第二张图的多余部分 output_size [max(rows1, rows2), cols1 cols2]; img2_registered imwarp(img2, tform, OutputView, imref2d(output_size));最开始我直接用imref2d(size(img1))结果拼出来的图只有第一张那么宽那不如不拼后来才知道得把总宽度拉到两张图的宽度之和。第三步用小波变换磨平拼接缝直接拼的话两张图的亮度差或者边缘会留下明显的缝用小波变换就能把这个缝给平滑掉。我写了个简单的融合函数function fused waveletFuse(imgA, imgB) % 转成double类型避免溢出 imgA im2double(imgA); imgB im2double(imgB); % 用db4小波做3层分解兼顾细节和平滑度 [C1, S1] wavedec2(imgA, 3, db4); [C2, S2] wavedec2(imgB, 3, db4); % 低频分量取平均保留整体亮度 low_freq (C1(1:S1(1,1)*S1(1,2)) C2(1:S2(1,1)*S2(1,2)))/2; % 高频分量取绝对值大的保留两张图的边缘细节 high_freq1 C1(S1(1,1)*S1(1,2)1:end); high_freq2 C2(S2(1,1)*S2(1,2)1:end); high_freq abs(high_freq1) abs(high_freq2) ? high_freq1 : high_freq2; % 合并分量重构图像 C [low_freq; high_freq]; fused waverec2(C, S1, db4); % 把亮度限制在正常范围内 fused(fused1) 1; fused(fused0) 0; fused im2uint8(fused); end一开始我直接用加权平均融合结果拼接缝还是很明显换成小波之后就自然多了连两张图之间的亮度差都给磨平了不少。第四步整个傻瓜式GUI总不能每次都敲命令行吧我用Matlab App Designer搭了个超简单的界面就三个按钮加一个显示框加载左图/右图按钮一键拼接按钮结果显示区核心的拼接逻辑直接把上面的代码塞到按钮回调里就行贴个简化版的app代码classdef StitchApp matlab.apps.AppBase properties (Access public) UIFigure, LoadLeft, LoadRight, StitchBtn ImgAxes, LeftImg, RightImg, FinalImg end methods (Access private) function loadLeft(app,~) [file,path] uigetfile({*.jpg;*.png,图片文件}); if ~isequal(file,0) app.LeftImg imread(fullfile(path,file)); imshow(app.LeftImg,Parent,app.ImgAxes); end end function runStitch(app,~) if isempty(app.LeftImg) || isempty(app.RightImg) uialert(app.UIFigure,先加载两张图啊喂,提示); return end % 这里把前面的SIFT匹配、变换、融合代码都放进去 % ... 省略重复代码 ... imshow(app.FinalImg,Parent,app.ImgAxes); end end end现在点两下按钮就能出全景图上次把拼好的公园湖景发朋友圈还有朋友问我用了啥专业修图软件其实就是几十行代码攒出来的小工具。最后唠两句踩过的坑要是两张图亮度差太多得先做个亮度均衡用imadjust调一下就行不然融合完还是会有明暗差SIFT的匹配阈值别乱调5左右刚好太小的话匹配点太少太大的话错配对变多小波分解层数别太高3层就够层数太多会把细节磨没整个工具虽然不如PS的全景功能专业但胜在完全开源随便改想调啥参数都能自己改折腾起来还挺有意思的。
基于SIFT与小波变换的图像拼接融合算法设计及Matlab实现GUI界面
基于SIFT和小波变换的图像拼接融合算法的设计与实现图像融合拼接GUI设计包括图像融合和图像拼接的Matlab实现上周去逛滨江公园拍了两张湖景照本来想拼个全景发朋友圈结果手动拖来拖去要么错位要么中间一条亮瞎眼的拼接缝折腾半小时还是翻车了。后来翻到之前攒的SIFT加小波变换的拼接代码改吧改吧终于搞出能用的东西今天跟大伙唠唠这个接地气的图像拼接工具。基于SIFT和小波变换的图像拼接融合算法的设计与实现图像融合拼接GUI设计包括图像融合和图像拼接的Matlab实现整个流程其实挺顺的先找两张图的共同特征点对齐再用小波变换把拼接缝磨平最后整个傻瓜式GUI不用敲命令行也能跑。第一步先把两张图的特征点对上首先得让两张图对齐不然拼出来就是两张歪歪扭扭的贴纸糊在一起。这里用SIFT找特征点不用自己手写算法新版Matlab自带的工具就够用省得调半天参数% 读入两张待拼接的图记得换成你自己的图片路径 img1 imread(park_left.jpg); img2 imread(park_right.jpg); % SIFT对灰度图更友好先转成单通道 gray1 rgb2gray(img1); gray2 rgb2gray(img2); % 提取特征点和对应的描述子 points1 detectSIFTFeatures(gray1); [features1, valid_pt1] extractFeatures(gray1, points1); points2 detectSIFTFeatures(gray2); [features2, valid_pt2] extractFeatures(gray2, points2); % 暴力匹配特征加个阈值过滤掉不靠谱的配对 match_pairs matchFeatures(features1, features2, MatchThreshold, 5); matched_pt1 valid_pt1(match_pairs(:,1),:); matched_pt2 valid_pt2(match_pairs(:,2),:);这里踩过坑一开始把MatchThreshold设成10结果匹配了一堆歪瓜裂枣的错配对拼出来的图直接歪到姥姥家改成5之后就清爽多了留下来的都是靠谱的对应点。第二步算出两张图的变换关系找到匹配点之后用单应矩阵把两张图掰到同一个坐标系里还要用RANSAC筛掉剩下的错配对不然还是会歪% 估计单应矩阵RANSAC自动过滤错配 [tform, inlier_idx] estimateGeometricTransform(matched_pt2, matched_pt1, projective); % 把第二张图变换到第一张图的视角下 [rows1, cols1, ~] size(img1); [rows2, cols2, ~] size(img2); % 得手动算好总画布尺寸不然会裁掉第二张图的多余部分 output_size [max(rows1, rows2), cols1 cols2]; img2_registered imwarp(img2, tform, OutputView, imref2d(output_size));最开始我直接用imref2d(size(img1))结果拼出来的图只有第一张那么宽那不如不拼后来才知道得把总宽度拉到两张图的宽度之和。第三步用小波变换磨平拼接缝直接拼的话两张图的亮度差或者边缘会留下明显的缝用小波变换就能把这个缝给平滑掉。我写了个简单的融合函数function fused waveletFuse(imgA, imgB) % 转成double类型避免溢出 imgA im2double(imgA); imgB im2double(imgB); % 用db4小波做3层分解兼顾细节和平滑度 [C1, S1] wavedec2(imgA, 3, db4); [C2, S2] wavedec2(imgB, 3, db4); % 低频分量取平均保留整体亮度 low_freq (C1(1:S1(1,1)*S1(1,2)) C2(1:S2(1,1)*S2(1,2)))/2; % 高频分量取绝对值大的保留两张图的边缘细节 high_freq1 C1(S1(1,1)*S1(1,2)1:end); high_freq2 C2(S2(1,1)*S2(1,2)1:end); high_freq abs(high_freq1) abs(high_freq2) ? high_freq1 : high_freq2; % 合并分量重构图像 C [low_freq; high_freq]; fused waverec2(C, S1, db4); % 把亮度限制在正常范围内 fused(fused1) 1; fused(fused0) 0; fused im2uint8(fused); end一开始我直接用加权平均融合结果拼接缝还是很明显换成小波之后就自然多了连两张图之间的亮度差都给磨平了不少。第四步整个傻瓜式GUI总不能每次都敲命令行吧我用Matlab App Designer搭了个超简单的界面就三个按钮加一个显示框加载左图/右图按钮一键拼接按钮结果显示区核心的拼接逻辑直接把上面的代码塞到按钮回调里就行贴个简化版的app代码classdef StitchApp matlab.apps.AppBase properties (Access public) UIFigure, LoadLeft, LoadRight, StitchBtn ImgAxes, LeftImg, RightImg, FinalImg end methods (Access private) function loadLeft(app,~) [file,path] uigetfile({*.jpg;*.png,图片文件}); if ~isequal(file,0) app.LeftImg imread(fullfile(path,file)); imshow(app.LeftImg,Parent,app.ImgAxes); end end function runStitch(app,~) if isempty(app.LeftImg) || isempty(app.RightImg) uialert(app.UIFigure,先加载两张图啊喂,提示); return end % 这里把前面的SIFT匹配、变换、融合代码都放进去 % ... 省略重复代码 ... imshow(app.FinalImg,Parent,app.ImgAxes); end end end现在点两下按钮就能出全景图上次把拼好的公园湖景发朋友圈还有朋友问我用了啥专业修图软件其实就是几十行代码攒出来的小工具。最后唠两句踩过的坑要是两张图亮度差太多得先做个亮度均衡用imadjust调一下就行不然融合完还是会有明暗差SIFT的匹配阈值别乱调5左右刚好太小的话匹配点太少太大的话错配对变多小波分解层数别太高3层就够层数太多会把细节磨没整个工具虽然不如PS的全景功能专业但胜在完全开源随便改想调啥参数都能自己改折腾起来还挺有意思的。