合并 2 个图像,将一个图像并排显示,用对角线分隔
Merging 2 images by showing one next to the other separated by a diagonal line
我有 2 张图片(“before”和“after”)。我想展示一张最终图像,其中左半部分取自 before 图像,右半部分取自 after 图像。
图像应由预定义宽度(2 或 3 个像素)的白色对角线分隔,其中对角线由特定角度或 2 个起点和终点坐标指定。对角线应覆盖最终图像的一部分,以便大小与来源相同。
示例:
我知道这可以通过遍历所有像素来重新组合并创建最终图像来完成,但是有没有一种有效的方法,或者更好的是,一个内置函数可以做到这一点?
一个解决方案:
im1 = imread('peppers.png');
im2 = repmat(rgb2gray(im1),1,1,3);
imgsplitter(im1,im2,80) %imgsplitter(image1,image2,angle [0-100])
function imgsplitter(im1,im2,p)
s1 = size(im1,1); s2 = size(im1,2);
pix = floor(p*size(im1,2)/100);
val = abs(pix -(s2-pix));
dia = imresize(tril(ones(s1)),[s1 val]);
len = min(abs([0-pix,s2-pix]));
if p>50
ind = [ones(s1,len) fliplr(~dia) zeros(s1,len)];
else
ind = [ones(s1,len) dia zeros(s1,len)];
end
ind = uint8(ind);
imshow(ind.*im1+uint8(~ind).*im2)
hold on
plot([pix,s2-pix],[0,s1],'w','LineWidth',1)
end
输出:
不幸的是,我不相信有解决您的问题的内置解决方案,但我已经开发了一些代码来帮助您做到这一点,但不幸的是,它需要图像处理工具箱才能很好地处理代码。正如您在评论中提到的,您已经有了这个,所以我们应该没问题。
这背后的逻辑比较简单。我们将假设您的前后图片大小相同,并且共享相同数量的频道。第一部分是声明一个空白图像,我们在一定厚度的中间画一条直线。这背后的复杂之处在于声明一个比图像的原始尺寸稍大的图像。原因是因为我要在中间画一条线,然后将这个空白图像旋转一定角度,以实现您想要的第一部分。我将使用 imrotate
将图像旋转任意角度。第一直觉是声明一个与原始图像大小相同的图像,在中间画一条线并旋转它。但是,如果您这样做,您最终会断开连接线,而不是从图像的顶部绘制到底部。这是有道理的,因为在一个角度上绘制的线比垂直绘制的线覆盖更多的像素。
利用毕达哥拉斯定理,我们知道可以在您的图像上绘制的最长直线是对角线。因此,我们声明一个图像在行和列中都是 sqrt(rows*rows + cols*cols)
,其中 rows
和 cols
是原始图像的行和列。之后,我们将采用天花板以确保我们已经覆盖了尽可能多的部分,并且我们添加了一些额外的空间来适应线条的宽度。我们在该图像上画一条线,旋转它,然后我们将 裁剪 图像,使其与输入图像大小相同。这样可以确保以您希望的任何角度绘制的线都是从上到下完整绘制的。
逻辑是最难的部分。一旦你这样做,你就声明了两个 logical
掩码,你使用 imfill
将掩码的左侧填充为一个掩码,我们将反转掩码以找到另一个掩码。您还需要使用我们之前使用 imrotate
创建的线条图像来索引掩码并将值设置为 false
以便我们忽略线上的这些像素。
最后,你取下每个蒙版,在你的图像中建立索引,然后复制你想要的图像的每个部分。您最终使用线条图像对输出进行索引并将值设置为白色。
事不宜迟,代码如下:
% Load some example data
load mandrill;
% im is the image before
% im2 is the image after
% Before image is a colour image
im = im2uint8(ind2rgb(X, map));
% After image is a grayscale image
im2 = rgb2gray(im);
im2 = cat(3, im2, im2, im2);
% Declare line image
rows = size(im, 1); cols = size(im, 2);
width = 5;
m = ceil(sqrt(rows*rows + cols*cols + width*width));
ln = false([m m]);
mhalf = floor(m / 2); % Find halfway point width wise and draw the line
ln(:,mhalf - floor(width/2) : mhalf + floor(width/2)) = true;
% Rotate the line image
ang = 20; % 20 degrees
lnrotate = imrotate(ln, ang, 'crop');
% Crop the image so that it's the same dimensions as the originals
mrowstart = mhalf - floor(rows/2);
mcolstart = mhalf - floor(cols/2);
lnfinal = lnrotate(mrowstart : mrowstart + rows - 1, mcolstart : mcolstart + cols - 1);
% Make the masks
mask1 = imfill(lnfinal, [1 1]);
mask2 = ~mask1;
mask1(lnfinal) = false;
mask2(lnfinal) = false;
% Make sure the masks have as many channels as the original
mask1 = repmat(mask1, [1 1 size(im,3)]);
mask2 = repmat(mask2, [1 1 size(im,3)]);
% Do the same for the line
lnfinal = repmat(lnfinal, [1 1 size(im, 3)]);
% Specify output image
out = zeros(size(im), class(im));
out(mask1) = im(mask1);
out(mask2) = im2(mask2);
out(lnfinal) = 255;
% Show the image
figure;
imshow(out);
我们得到:
如果您希望直线朝另一个方向延伸,只需将角度 ang
设置为负值即可。在上面的示例脚本中,我将角度逆时针旋转 20 度(即正)。要重现您提供的示例,请改为指定 -20 度。我现在得到这张图片:
这是一个使用多边形的解决方案:
function q44310306
% Load some image:
I = imread('peppers.png');
B = rgb2gray(I);
lt = I; rt = B;
% Specify the boundaries of the white line:
width = 2; % [px]
offset = 13; % [px]
sz = size(I);
wlb = [floor(sz(2)/2)-offset+[0,width]; ceil(sz(2)/2)+offset-[width,0]];
% [top-left, top-right; bottom-left, bottom-right]
% Configure two polygons:
leftPoly = struct('x',[1 wlb(1,2) wlb(2,2) 1], 'y',[1 1 sz(1) sz(1)]);
rightPoly = struct('x',[sz(2) wlb(1,1) wlb(2,1) sz(2)],'y',[1 1 sz(1) sz(1)]);
% Define a helper grid:
[XX,YY] = meshgrid(1:sz(2),1:sz(1));
rt(inpolygon(XX,YY,leftPoly.x,leftPoly.y)) = intmin('uint8');
lt(repmat(inpolygon(XX,YY,rightPoly.x,rightPoly.y),1,1,3)) = intmin('uint8');
rt(inpolygon(XX,YY,leftPoly.x,leftPoly.y) & ...
inpolygon(XX,YY,rightPoly.x,rightPoly.y)) = intmax('uint8');
final = bsxfun(@plus,lt,rt);
% Plot:
figure(); imshow(final);
结果:
我有 2 张图片(“before”和“after”)。我想展示一张最终图像,其中左半部分取自 before 图像,右半部分取自 after 图像。
图像应由预定义宽度(2 或 3 个像素)的白色对角线分隔,其中对角线由特定角度或 2 个起点和终点坐标指定。对角线应覆盖最终图像的一部分,以便大小与来源相同。
示例:
我知道这可以通过遍历所有像素来重新组合并创建最终图像来完成,但是有没有一种有效的方法,或者更好的是,一个内置函数可以做到这一点?
一个解决方案:
im1 = imread('peppers.png');
im2 = repmat(rgb2gray(im1),1,1,3);
imgsplitter(im1,im2,80) %imgsplitter(image1,image2,angle [0-100])
function imgsplitter(im1,im2,p)
s1 = size(im1,1); s2 = size(im1,2);
pix = floor(p*size(im1,2)/100);
val = abs(pix -(s2-pix));
dia = imresize(tril(ones(s1)),[s1 val]);
len = min(abs([0-pix,s2-pix]));
if p>50
ind = [ones(s1,len) fliplr(~dia) zeros(s1,len)];
else
ind = [ones(s1,len) dia zeros(s1,len)];
end
ind = uint8(ind);
imshow(ind.*im1+uint8(~ind).*im2)
hold on
plot([pix,s2-pix],[0,s1],'w','LineWidth',1)
end
输出:
不幸的是,我不相信有解决您的问题的内置解决方案,但我已经开发了一些代码来帮助您做到这一点,但不幸的是,它需要图像处理工具箱才能很好地处理代码。正如您在评论中提到的,您已经有了这个,所以我们应该没问题。
这背后的逻辑比较简单。我们将假设您的前后图片大小相同,并且共享相同数量的频道。第一部分是声明一个空白图像,我们在一定厚度的中间画一条直线。这背后的复杂之处在于声明一个比图像的原始尺寸稍大的图像。原因是因为我要在中间画一条线,然后将这个空白图像旋转一定角度,以实现您想要的第一部分。我将使用 imrotate
将图像旋转任意角度。第一直觉是声明一个与原始图像大小相同的图像,在中间画一条线并旋转它。但是,如果您这样做,您最终会断开连接线,而不是从图像的顶部绘制到底部。这是有道理的,因为在一个角度上绘制的线比垂直绘制的线覆盖更多的像素。
利用毕达哥拉斯定理,我们知道可以在您的图像上绘制的最长直线是对角线。因此,我们声明一个图像在行和列中都是 sqrt(rows*rows + cols*cols)
,其中 rows
和 cols
是原始图像的行和列。之后,我们将采用天花板以确保我们已经覆盖了尽可能多的部分,并且我们添加了一些额外的空间来适应线条的宽度。我们在该图像上画一条线,旋转它,然后我们将 裁剪 图像,使其与输入图像大小相同。这样可以确保以您希望的任何角度绘制的线都是从上到下完整绘制的。
逻辑是最难的部分。一旦你这样做,你就声明了两个 logical
掩码,你使用 imfill
将掩码的左侧填充为一个掩码,我们将反转掩码以找到另一个掩码。您还需要使用我们之前使用 imrotate
创建的线条图像来索引掩码并将值设置为 false
以便我们忽略线上的这些像素。
最后,你取下每个蒙版,在你的图像中建立索引,然后复制你想要的图像的每个部分。您最终使用线条图像对输出进行索引并将值设置为白色。
事不宜迟,代码如下:
% Load some example data
load mandrill;
% im is the image before
% im2 is the image after
% Before image is a colour image
im = im2uint8(ind2rgb(X, map));
% After image is a grayscale image
im2 = rgb2gray(im);
im2 = cat(3, im2, im2, im2);
% Declare line image
rows = size(im, 1); cols = size(im, 2);
width = 5;
m = ceil(sqrt(rows*rows + cols*cols + width*width));
ln = false([m m]);
mhalf = floor(m / 2); % Find halfway point width wise and draw the line
ln(:,mhalf - floor(width/2) : mhalf + floor(width/2)) = true;
% Rotate the line image
ang = 20; % 20 degrees
lnrotate = imrotate(ln, ang, 'crop');
% Crop the image so that it's the same dimensions as the originals
mrowstart = mhalf - floor(rows/2);
mcolstart = mhalf - floor(cols/2);
lnfinal = lnrotate(mrowstart : mrowstart + rows - 1, mcolstart : mcolstart + cols - 1);
% Make the masks
mask1 = imfill(lnfinal, [1 1]);
mask2 = ~mask1;
mask1(lnfinal) = false;
mask2(lnfinal) = false;
% Make sure the masks have as many channels as the original
mask1 = repmat(mask1, [1 1 size(im,3)]);
mask2 = repmat(mask2, [1 1 size(im,3)]);
% Do the same for the line
lnfinal = repmat(lnfinal, [1 1 size(im, 3)]);
% Specify output image
out = zeros(size(im), class(im));
out(mask1) = im(mask1);
out(mask2) = im2(mask2);
out(lnfinal) = 255;
% Show the image
figure;
imshow(out);
我们得到:
如果您希望直线朝另一个方向延伸,只需将角度 ang
设置为负值即可。在上面的示例脚本中,我将角度逆时针旋转 20 度(即正)。要重现您提供的示例,请改为指定 -20 度。我现在得到这张图片:
这是一个使用多边形的解决方案:
function q44310306
% Load some image:
I = imread('peppers.png');
B = rgb2gray(I);
lt = I; rt = B;
% Specify the boundaries of the white line:
width = 2; % [px]
offset = 13; % [px]
sz = size(I);
wlb = [floor(sz(2)/2)-offset+[0,width]; ceil(sz(2)/2)+offset-[width,0]];
% [top-left, top-right; bottom-left, bottom-right]
% Configure two polygons:
leftPoly = struct('x',[1 wlb(1,2) wlb(2,2) 1], 'y',[1 1 sz(1) sz(1)]);
rightPoly = struct('x',[sz(2) wlb(1,1) wlb(2,1) sz(2)],'y',[1 1 sz(1) sz(1)]);
% Define a helper grid:
[XX,YY] = meshgrid(1:sz(2),1:sz(1));
rt(inpolygon(XX,YY,leftPoly.x,leftPoly.y)) = intmin('uint8');
lt(repmat(inpolygon(XX,YY,rightPoly.x,rightPoly.y),1,1,3)) = intmin('uint8');
rt(inpolygon(XX,YY,leftPoly.x,leftPoly.y) & ...
inpolygon(XX,YY,rightPoly.x,rightPoly.y)) = intmax('uint8');
final = bsxfun(@plus,lt,rt);
% Plot:
figure(); imshow(final);
结果: