【问题标题】:Merging 2 images by showing one next to the other separated by a diagonal line通过显示一个并排显示由对角线分隔的另一个图像来合并 2 个图像
【发布时间】:2017-06-01 14:30:04
【问题描述】:

我有 2 张图片(“之前”和“之后”)。我想展示一个最终图像,其中左半部分取自 before 图像,右半部分取自 after 图像。

图像应由一条预定义宽度(2 或 3 像素)的白色对角线分隔,其中对角线由某个角度或 2 个起点和终点坐标指定。对角线应覆盖最终图像的一部分,使其大小与源相同。

例子:

我知道这可以通过循环所有像素来重新组合并创建最终图像来完成,但是有没有一种有效的方法,或者更好的是,一个内置函数可以做到这一点?

【问题讨论】:

  • 所以你想要一张分解成三部分的图像...第一部分是前一张图像的左半部分,中间是一张 2 或 3 像素宽的白线图像但是以某个角度旋转,最后一部分是后图像的右半部分?可以举个例子吗?
  • 是的,我在编辑中添加了一个示例。
  • 啊哈。这个例子说明了一切。感谢您添加它。你有没有偶然的图像处理工具箱?
  • 白线应该覆盖图像的一部分,从而产生相同大小的图像还是将它们分开?
  • @rayreng 是的,我愿意,Leander 它应该覆盖,以便最终图像大小与原始 2 个图像相同

标签: image matlab merge image-manipulation image-comparison


【解决方案1】:

很遗憾,我认为没有内置解决方案可以解决您的问题,但我已经开发了一些代码来帮助您解决此问题,但不幸的是,它需要图像处理工具箱才能很好地与代码配合使用。正如您的 cmets 中提到的,您已经有了这个,所以我们应该没问题。

这背后的逻辑比较简单。我们将假设您的前后图片大小相同,并且共享相同数量的通道。第一部分是声明一个空白图像,我们在一定厚度的中间画一条直线。这背后的复杂性在于声明一个比图像的原始大小略大的图像。原因是因为我要在中间画一条线,然后将这个空白图像旋转一定角度,以达到你想要的第一部分。我将使用imrotate 将图像旋转您想要的任何角度。第一个直觉是声明一个与原件大小相同的图像,在中间画一条线并旋转它。但是,如果你这样做,你最终会断开线,而不是从图像的顶部到底部绘制。这是有道理的,因为在某个角度上绘制的线比垂直绘制时覆盖的像素更多。

使用勾股定理,我们知道可以在图像上绘制的最长线是对角线。因此,我们在rowscols 是原始图像的行和列的行和列中声明一个图像为sqrt(rows*rows + cols*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 度。我现在得到这张图片:

【讨论】:

  • 我收到 zeros 函数错误:错误使用 zeros CLASSNAME 输入必须是有效的数字类名。我认为不支持输入字符串“逻辑”。
  • @StackPlayer 您可能使用的是旧版本的 MATLAB。它适用于 R2016b。我已对其进行了更改,使其适用于旧版本。
  • @StackPlayer 哈哈没问题 :) 谢谢采纳!这是一个有趣的问题。我第一次做过这样的事情。
  • @StackPlayer 好的,我已经修好了。我刚刚在裁剪之前为线条图像添加了更多填充。让我知道它是否有效。
  • 一个伟大的,一如既往,雷!
【解决方案2】:

这是一个使用多边形的解决方案:

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);

结果:

【讨论】:

    【解决方案3】:

    一种解决方案:

    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
    

    输出:

    【讨论】:

      猜你喜欢
      • 2021-10-14
      • 1970-01-01
      • 2014-06-21
      • 1970-01-01
      • 1970-01-01
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多