37

シンシティや他の映画に似た効果を作成しようとしています。これらの効果では、画像から1つを除くすべての色が削除されます。

グレースケールに変換したいRGB画像がありますが、1色のままにしておきたいです。

これは私の写真です:

代替テキスト

赤い色を保ちたいです。残りはグレースケールである必要があります。

これは私のコードがこれまでに出力したものです(領域が正しいことがわかりますが、なぜそれらが赤ではなく白であるのかわかりません):

代替テキスト

これまでの私のコードは次のとおりです。

filename = 'roses.jpg';

[cdata,map] = imread( filename );
% convert to RGB if it is indexed image
if ~isempty( map ) 
   cdata = idx2rgb( cdata, map ); 
end

%imtool('roses.jpg');

imWidth = 685;
imHeight = 428;

% RGB ranges of a color we want to keep
redRange = [140 255];
greenRange = [0 40];
blueRange = [0 40];

% RGB values we don't want to convert to grayscale
redToKeep = zeros(imHeight, imWidth);
greenToKeep = zeros(imHeight, imWidth);
blueToKeep = zeros(imHeight, imWidth);

for x=1:imWidth

    for y=1:imHeight

        red = cdata( y, x, 1 );
        green = cdata( y, x, 2 );
        blue = cdata( y, x, 3 );

        if (red >= redRange(1) && red <= redRange(2) && green >= greenRange(1) && green <= greenRange(2) && blue >= blueRange(1) && blue <= blueRange(2))
            redToKeep( y, x ) = red;
            greenToKeep( y, x ) = green;
            blueToKeep( y, x ) = blue;
        else
            redToKeep( y, x ) = 999;
            greenToKeep( y, x ) = 999;
            blueToKeep( y, x ) = 999;
        end

    end 

end 

im = rgb2gray(cdata);
[X, map] = gray2ind(im);
im = ind2rgb(X, map);

for x=1:imWidth

    for y=1:imHeight

        if (redToKeep( y, x ) < 999)
            im( y, x, 1 ) = 240;
        end
        if (greenToKeep( y, x ) < 999)
            im( y, x, 2 ) = greenToKeep( y, x );
        end
        if (blueToKeep( y, x ) < 999)
            im( y, x, 3 ) = blueToKeep( y, x );
        end

    end 

end 

imshow(im);
4

3 に答える 3

88

結果の画像の品質を大幅に向上させるオプションの 1 つは、色をより簡単に選択できるように別の色空間に変換することです。特に、HSV 色空間は、色相 (色)、彩度 (色の量)、値 (色の明るさ) の観点からピクセルの色を定義します。

たとえば、関数 を使用して RGB 画像を HSV 空間に変換し、rgb2hsv「赤以外の」色として定義したい色相 (たとえば、20 度から 340 度など) にまたがる色相を持つピクセルを見つけ、彩度を設定することができます。これらのピクセルを 0 (グレースケール) にしてから、次の関数を使用して画像を RGB 空間に変換しますhsv2rgb

cdata = imread('EcyOd.jpg');       % Load image
hsvImage = rgb2hsv(cdata);         % Convert the image to HSV space
hPlane = 360.*hsvImage(:, :, 1);   % Get the hue plane scaled from 0 to 360
sPlane = hsvImage(:, :, 2);        % Get the saturation plane
nonRedIndex = (hPlane > 20) & ...  % Select "non-red" pixels
              (hPlane < 340);
sPlane(nonRedIndex) = 0;           % Set the selected pixel saturations to 0
hsvImage(:, :, 2) = sPlane;        % Update the saturation plane
rgbImage = hsv2rgb(hsvImage);      % Convert the image back to RGB space

結果の画像は次のとおりです。

代替テキスト

zellus のソリューションと比較して、花の淡いピンク色を簡単に維持できることに注目してください。茎と地面の茶色がかった色調もなくなっていることにも注意してください.

色のプロパティに基づいて画像からオブジェクトを選択するクールな例については、Steve Eddins のブログ投稿The Two Amigosを参照してください。この記事では、MathWorks の Brett Shoelson が画像から 1 つの「amigo」を抽出するソリューションについて説明しています。


色の範囲を選択する際の注意...

色の範囲を選択するのに役立つもう 1 つhPlaneの方法は、HSV 画像のピクセルに存在する色相のヒストグラム (上から) を調べることです。histc関数(または、histcounts利用可能な場合は推奨される ) とを使用する例を次に示しますbar

binEdges = 0:360;    % Edges of histogram bins
hFigure = figure();  % New figure

% Bin pixel hues and plot histogram:
if verLessThan('matlab', '8.4')
  N = histc(hPlane(:), binEdges);  % Use histc in older versions
  hBar = bar(binEdges(1:end-1), N(1:end-1), 'histc');
else
  N = histcounts(hPlane(:), binEdges);
  hBar = bar(binEdges(1:end-1), N, 'histc');
end

set(hBar, 'CData', 1:360, ...            % Change the color of the bars using
          'CDataMapping', 'direct', ...  %   indexed color mapping (360 colors)
          'EdgeColor', 'none');          %   and remove edge coloring
colormap(hsv(360));                      % Change to an HSV color map with 360 points
axis([0 360 0 max(N)]);                  % Change the axes limits
set(gca, 'Color', 'k');                  % Change the axes background color
set(hFigure, 'Pos', [50 400 560 200]);   % Change the figure size
xlabel('HSV hue (in degrees)');          % Add an x label
ylabel('Bin counts');                    % Add a y label

結果のピクセル カラー ヒストグラムは次のとおりです。

代替テキスト

元の画像には、主に赤、緑、黄色のピクセルが含まれていることに注意してください (オレンジ色のピクセルがいくつかあります)。シアン、ブルー、インディゴ、マゼンタの色のピクセルはほとんどありません。上で選択した範囲 (20 ~ 340 度) は、両端にある 2 つの大きな赤いクラスターの一部ではないほとんどすべてをうまく除外していることにも注意してください。

于 2010-10-31T17:33:45.540 に答える
19
figure
pic = imread('EcyOd.jpg');

for mm = 1:size(pic,1)
    for nn = 1:size(pic,2)
        if pic(mm,nn,1) < 80 || pic(mm,nn,2) > 80 || pic(mm,nn,3) > 100
            gsc = 0.3*pic(mm,nn,1) + 0.59*pic(mm,nn,2) + 0.11*pic(mm,nn,3);
            pic(mm,nn,:) = [gsc gsc gsc];
        end
    end
end
imshow(pic)

代替テキスト

于 2010-10-31T17:41:52.400 に答える
2

私は matlab がどのように機能するのかよくわからないので、コードについてコメントすることはできませんが、RGB カラーがどのように機能するかを少し説明するのに役立つかもしれません。

RGB カラーを使用する場合、R、G、B の値がすべて同じであることを確認することでグレースケールを作成できます。したがって、基本的にやりたいことは、R、G、Bを同じにするだけでなく、ピクセルが赤かどうかを検出することです(基本的な結果には3の平均を使用できます)。

より難しい部分は、ピクセルが実際に赤であるかどうかを検出する方法です。ピクセルの R 値が高いかどうかを確認することはできません。これは、別の色である可能性があるためです。R 値が低い場合は、単に暗い赤を意味する可能性があります。

あなたはこのようなことをすることができます:(私はmatlabを持っていないので、構文を想定しています):

赤 = cdata( y, x, 1 );
緑 = cdata(y, x, 2);
青 = cdata(y, x, 3);

if (赤 < (青 * 1.4) || 赤 < (緑 * 1.4) )
{
    平均 = (赤 + 緑 + 青) / 3;
    cdata(y, x, 1) = 平均;
    cdata(y, x, 2) = 平均;
    cdata(y, x, 3) = 平均;
}

赤を検出して平均的な灰色を得るには、おそらくもっと良い方法がありますが、それは出発点です ;)

于 2010-10-31T17:19:48.980 に答える