首页 文章

将图像放在另一个图像的黑色像素中

提问于
浏览
2

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

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

为了做到这一点:

  • 我在主图像中找到了黑色像素

  • 将次映像调整为我想要的特定大小

  • 在我在第一步中找到的每个坐标中绘制图像 . (黑色像素应该是次要图像的中心坐标)

不幸的是,我不知道如何做第三步 .

例如:

主要形象是:

enter image description here

次要形象是:

enter image description here

输出:

enter image description here

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

这是我的代码:

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

任何帮助赞赏!

2 回答

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

    我们得到:

    enter image description here


    编辑

    我没有被告知你的图像有透明度 . 因此,您需要做的是使用 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...
    % ...
    

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

    enter image description here

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

    enter image description here

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

相关问题