【问题标题】:Place image in black pixels of another image将图像放置在另一个图像的黑色像素中
【发布时间】:2017-10-04 17:10:50
【问题描述】:

我有一个名为main.jpg(主图像)的图像(白色背景,带有 1-5 个黑点)。

我正在尝试在主图像中找到的每个黑点中放置另一个图像 (secondary.jpg)。

为了做到这一点:

  1. 我发现主图像中有黑色像素
  2. 将次要图像调整为我想要的特定大小
  3. 在我在第一步中找到的每个坐标中绘制图像。 (黑色像素应该是次图像的中心坐标)

不幸的是,我不知道如何进行第三步。

例如:

主图是:

次要图片是:

输出:

(点在椅子后面。它们是图像中心点)

这是我的代码:

mainImage=imread('main.jpg')
secondaryImage=imread('secondary.jpg')
secondaryImageResized = resizeImage(secondaryImage)
[m n]=size(mainImage)
 for i=1:n
     for j=1:m
         % if it's black pixel
         if (mainImage(i,j)==1)
            outputImage = plotImageInCoordinates(secondaryImageResized, i, j)
            % save this image
            imwrite(outputImage,map,'clown.bmp')
         end
    end
end


% resize the image to (250,350) width, height
function [ Image ] = resizeImage(img)
    image = imresize(img, [250 350]); 
end


function [outputImage] = plotImageInCoordinates(image, x, y)
    % Do something
end

任何帮助表示赞赏!

【问题讨论】:

    标签: image matlab image-processing


    【解决方案1】:

    这是一个没有卷积的替代方案。您必须考虑的一个复杂问题是,如果要将每个图像放在每个点的中心,则必须确定左上角的位置并索引到输出图像,以便从左上角绘制所需的对象角落到右下角。您可以通过获取每个黑点位置并水平减去一半宽度和垂直减去一半高度来做到这一点。

    现在谈谈你的实际问题。如果您遍历一组黑色的点,而不是整个图像,效率会更高。您可以通过使用find 命令来确定为0 的行和列位置来执行此操作。执行此操作后,循环遍历每对行和列坐标,减去坐标,然后将其放在输出中图片。

    我将在对象可能重叠的地方施加额外的要求。为了适应这一点,我将累积像素,然后找到非零位置的平均值。

    为适应这种情况而修改的代码如下。请注意,因为您使用的是 JPEG 压缩,所以您将有压缩伪影,因此为 0 的区域可能不一定为 0。我将使用 128 的强度阈值以确保零区域实际上为零。您还会遇到对象可能超出图像边界的情况。因此,为了适应这种情况,请在水平方向用一半宽度的两倍和垂直一半高度的两倍填充图像,然后在放置对象后对其进行裁剪。

    mainImage=imread('https://i.stack.imgur.com/gbhWJ.png');
    secondaryImage=imread('https://i.stack.imgur.com/P0meM.png');
    secondaryImageResized = imresize(secondaryImage, [250 300]);
    
    % Find half height and width
    rows = size(secondaryImageResized, 1);
    cols = size(secondaryImageResized, 2);
    halfHeight = floor(rows / 2);
    halfWidth = floor(cols / 2);
    
    % Create a padded image that contains our main image.  Pad with white
    % pixels.
    rowsMain = size(mainImage, 1);
    colsMain = size(mainImage, 2);
    outputImage = 255*ones([2*halfHeight + rowsMain, 2*halfWidth + colsMain, size(mainImage, 3)], class(mainImage));
    outputImage(halfHeight + 1 : halfHeight + rowsMain, ...
            halfWidth + 1 : halfWidth + colsMain, :) = mainImage;
    
    % Find a mask of the black pixels
    mask = outputImage(:,:,1) < 128;
    
    % Obtain black pixel locations
    [row, col] = find(mask);
    
    % Reset the output image so that they're all zeros now.  We use this
    % to output our final image.  Also cast to ensure accumulation is proper.
    outputImage(:) = 0;
    outputImage = double(outputImage);
    
    % Keeps track of how many times each pixel was hit by the object
    % This is so that we can find the average at each location.
    counts = zeros([size(mask), size(mainImage, 3)]);
    
    % For each row and column location in the image    
    for i = 1 : numel(row)
        % Get the row and column locations
        r = row(i); c = col(i);
    
        % Offset to get the top left corner
        r = r - halfHeight;
        c = c - halfWidth;
    
        % Place onto final image
        outputImage(r:r+rows-1, c:c+cols-1, :) = outputImage(r:r+rows-1, c:c+cols-1, :) + double(secondaryImageResized);
    
        % Accumulate the counts
        counts(r:r+rows-1,c:c+cols-1,:) = counts(r:r+rows-1,c:c+cols-1,:) + 1;
    end
    
    % Find average - Any values that were not hit, change to white
    outputImage = outputImage ./ counts;
    outputImage(counts == 0) = 255;
    outputImage = uint8(outputImage);
    
    % Now crop and show
    outputImage = outputImage(halfHeight + 1 : halfHeight + rowsMain, ...
            halfWidth + 1 : halfWidth + colsMain, :);
    close all; imshow(outputImage);
    
    % Write the final output
    imwrite(outputImage, 'finalimage.jpg', 'Quality', 100);
    

    我们得到:


    编辑

    没有人告诉我您的图片具有透明度。因此,您需要做的是使用imread,但请确保您在 Alpha 通道中阅读。然后我们检查是否存在一个,如果存在,我们将确保任何没有透明度的值的背景设置为白色。您可以使用以下代码执行此操作。确保将其放置在代码的最顶部,替换正在加载的图像:

    mainImage=imread('https://i.stack.imgur.com/gbhWJ.png');
    
    % Change - to accommodate for transparency
    [secondaryImage, ~, alpha] = imread('https://i.imgur.com/qYJSzEZ.png');
    if ~isempty(alpha)
        m = alpha == 0;
        for i = 1 : size(secondaryImage,3)
            m2 = secondaryImage(:,:,i);
            m2(m) = 255;
            secondaryImage(:,:,i) = m2;
        end
    end
    
    secondaryImageResized = imresize(secondaryImage, [250 300]);
    
    % Rest of your code follows...
    % ...
    

    上面的代码已经被修改为可以读取篮球图像。其余代码保持不变,因此我们得到:

    【讨论】:

    • 非常感谢您的帮助!不幸的是,它不适用于此图像:i.imgur.com/qYJSzEZ.png
    • 球有黑色背景:i.imgur.com/bteofvh.jpg 虽然图片没有...
    • 那是因为你的图像有一个 alpha 通道。我将不得不更改我的代码。
    • @AlonShmiel 完成。看看吧。
    【解决方案2】:

    您可以使用convolution 来达到想要的效果。这将在imz 中的黑点处放置im 的副本。

    % load secondary image
    im = double(imread('secondary.jpg'))/255.0;
    
    % create some artificial image with black indicators
    imz = ones(500,500,3);
    imz(50,50,:) = 0;
    imz(400,200,:) = 0;
    imz(200,400,:) = 0;
    
    % create output image
    imout = zeros(size(imz));
    imout(:,:,1) = conv2(1-imz(:,:,1),1-im(:,:,1),'same');
    imout(:,:,2) = conv2(1-imz(:,:,2),1-im(:,:,2),'same');
    imout(:,:,3) = conv2(1-imz(:,:,3),1-im(:,:,3),'same');
    imout = 1-imout;
    
    % output
    imshow(imout);
    

    此外,您可能希望避免将main.jpg 保存为.jpg,因为它会导致有损压缩,并且可能会导致任何依赖精确像素值的方法出现问题。我建议使用.png,它是无损的,并且对于相同颜色重复多次的合成图像,它的压缩效果也可能比.jpg 更好。

    【讨论】:

    • 嗨@jodag。我试过这张图片:i.imgur.com/qYJSzEZ.png,输出背景是黑色而不是白色..(我试图将 png 转换为 jpg)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 2015-05-05
    • 2013-01-29
    • 1970-01-01
    相关资源
    最近更新 更多