Чтобы преобразовать только черный цвет в белый в Matlab

Я знаю нить о преобразовании черного цвета в белый и белый в черный одновременно. Я хотел бы преобразовать только черное в белое. Я знаю это нить об этом я спрашиваю, но я не понимаю что идет не так.

картинка

enter image description here

код

rgbImage = imread('ecg.png');
grayImage = rgb2gray(rgbImage); % for non-indexed images
level = graythresh(grayImage); % threshold for converting image to binary, 
binaryImage = im2bw(grayImage, level); 
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
% Make the black parts pure red.
redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 0;
blueChannel(~binaryImage) = 0;
% Now recombine to form the output image.
rgbImageOut = cat(3, redChannel, greenChannel, blueChannel);
imshow(rgbImageOut);

что дает

enter image description here

где, кажется, что-то не так в канале красного цвета. Этот Черный цвет просто (0,0,0) в RGB, поэтому его удаление должно означать превращение каждого (0,0,0) пикселя в белый (255,255,255). Делать эту идею с

redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;

дает

enter image description here

поэтому я, должно быть, неправильно понял что-то в Matlab. Синий цвет не должен иметь черного. Так что последнее изображение странное.

как вы можете превратить только черный цвет в белый? Я хочу сохранить голубой цвет ЭКГ.

4 ответов


в чем проблема?

вы хотите обнаружить все черные части изображения, но они на самом деле не черный

пример:

enter image description here

ваша идея (или код):

вы первый бинаризация изображения, выбора пикселей, которые что-то против пикселей, которые не являются. Короче говоря, вы делаете:if pixel>level; pixel is something

поэтому у вас есть небольшое заблуждение! когда ты пишешь

% Make the black parts pure red.

следует читать

% Make every pixel that is something (not background) pure red.

поэтому, когда вы делаете

redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;

Вы делаете

% Make every pixel that is something (not background) white 
% (or what it is the same in this case, delete them).

поэтому то, что вы должны сделать-это полностью белое изображение. Изображение не полностью белое, потому что были некоторые пиксели, которые были помечены как "не что-то, часть фона" значением level в случае вашего изображения около 0,6.

решение, которое можно было бы придумать вручную установка уровня в 0.05 или аналогичный, так что только черные пиксели будут выбраны в сером двоичном трихолдинге. но это не будет работать на 100%, как вы можете видеть, цифры имеют некоторые очень "черные" значения.


как бы я попытался решить проблему:

Я бы попытался найти цвет, который вы хотите, извлечь только этот цвет из изображения, а затем удалить выбросы.

извлечь синий с помощью HSV (я считаю, что ответил вы где-то еще, как использовать HSV).

rgbImage = imread('ecg.png');
hsvImage=rgb2hsv(rgbImage);
I=rgbImage;
R=I(:,:,1);
G=I(:,:,2);
B=I(:,:,3);
th=0.1;
R((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
G((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
B((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
I2= cat(3, R, G, B);

imshow(I2)

enter image description here

здесь мы хотели бы получить самую большую синюю часть, и это было бы нашим сигналом. Поэтому самый лучший подход, кажется, первый бинаризация изображения, принимать все синие пикселы

% Binarize image, getting all the pixels that are "blue"
bw=im2bw(rgb2gray(I2),0.9999);

а затем с помощью bwlabel, обозначьте все независимые пиксельные "острова".

% Label each "blob"
lbl=bwlabel(~bw);

наиболее повторяемой меткой будет сигнал. Таким образом, мы находим его и отделяем фон от сигнала, используя этот ярлык.

% Find the blob with the highes amount of data. That  will be your signal.
r=histc(lbl(:),1:max(lbl(:)));
[~,idxmax]=max(r);
% Profit!
signal=rgbImage;
signal(repmat((lbl~=idxmax),[1 1 3]))=255;
background=rgbImage;
background(repmat((lbl==idxmax),[1 1 3]))=255;

здесь есть график с сигналом, фоном и разностью (используя то же уравнение, что и @rayryang)

enter image description here


если я правильно вас понимаю, вы хотите извлечь синий график ЭКГ при удалении текста и осей. Лучший способ сделать это - изучить цветовое пространство HSV изображения. Цветовое пространство HSV отлично подходит для различения цветов, как и у людей. Мы можем ясно видеть, что на изображении есть два разных цвета.

мы можем преобразовать изображение в HSV, используя rgb2hsv и мы можем рассмотреть компоненты отдельно. Компонент оттенка представляет доминирующий цвет пикселя, насыщенность обозначает чистоту или количество белого света в пикселе, а значение представляет интенсивность или силу пикселя.

попробуйте визуализировать каждый канал, делая:

im = imread('http://i.stack.imgur.com/cFOSp.png'); %// Read in your image
hsv = rgb2hsv(im);
figure;
subplot(1,3,1); imshow(hsv(:,:,1)); title('Hue');
subplot(1,3,2); imshow(hsv(:,:,2)); title('Saturation');
subplot(1,3,3); imshow(hsv(:,:,3)); title('Value');

enter image description here

Мда... ну оттенок и насыщенность не помогает. Это говорит нам, что доминирующий цвет и насыщение одинаковы... но их отличает то, что стоимостью. Если вы посмотрите на изображение справа, мы сможем различить их по силе самого цвета. Так что это говорит нам о том, что" черные " пиксели на самом деле синие, но почти без силы, связанной с ним.

мы можем использовать это в наших интересах. Любые пиксели, значения которых выше определенного значения, являются значениями, которые мы хотим сохранить.

попробуйте установить порог... что-то вроде 0.75. Динамический диапазон MATLAB HSV значения от [0-1], так:

mask = hsv(:,:,3) > 0.75;

когда мы пороговое значение компонента, это то, что мы получаем:

enter image description here

очевидно, что есть немного шума квантования... особенно вокруг топоров и шрифта. То, что я собираюсь сделать дальше, это выполнить морфологический эрозия так что я могу устранить шум квантования, что вокруг каждого из чисел и осей. Я собираюсь сделать маску немного большой, чтобы убедиться, что я удалю это шум. Использование панели инструментов обработка изображений:

se = strel('square', 5);
mask_erode = imerode(mask, se);

мы получаем это:

enter image description here

отлично, так что я собираюсь сделать сейчас, это сделать копию исходного изображения, а затем установить любой пиксель, который черный от маски, которую я получил (выше) до белого цвета на конечном изображении. Все остальные пиксели должны оставаться нетронутыми. Таким образом, мы можем удалить любой текст и топоры виден на изображении:

im_final = im;
mask_final = repmat(mask_erode, [1 1 3]);
im_final(~mask_final) = 255;

мне нужно скопировать маску в третье измерение, потому что это цветное изображение, и мне нужно установить каждый канал на 255 одновременно в тех же пространственных местоположениях.

когда я это делаю, вот что я получаю:

enter image description here

теперь вы заметите, что есть пробелы в графике.... что следует ожидать из-за шума квантования. Мы можем сделать что-то еще, преобразовав это изображение в оттенки серого и удерживая изображение, а затем заполнив соединение краев морфологическим расширение. Это безопасно, потому что мы уже устранили аксиомы и текст. Затем мы можем использовать это как маску для индексации в исходное изображение для получения нашего окончательного графика.

что-то вроде этого:

im2 = rgb2gray(im_final);
thresh = im2 < 200;
se = strel('line', 10, 90);
im_dilate = imdilate(thresh, se);
mask2 = repmat(im_dilate, [1 1 3]);
im_final_final = 255*ones(size(im), class(im));
im_final_final(mask2) = im(mask2);

Я пороговое предыдущее изображение, которое мы получили без текста и осей после преобразования его в оттенки серого, а затем я выполняю расширение с строка структурирующий элемент, который составляет 90 градусов, чтобы соединить те линии, которые были первоначально разъединенный. Это пороговое изображение будет содержать пиксели, которые мы в конечном счете должны отобрать из исходного изображения, чтобы мы могли получить необходимые данные графика.

затем я беру эту маску, повторить ее, сделать полностью белое изображение, а затем образец из исходного изображения и место расположения мы хотим от исходного изображения в белые изображения.

это наше окончательное изображение:

enter image description here

очень приятно! Я должен был сделать весь этот образ обработка, потому что ваше изображение в основном имеет шум квантования, поэтому будет немного сложнее получить график полностью. Андер Бигури в своем ответе объяснил более подробно о шуме цветового квантования, поэтому, безусловно, ознакомьтесь с его сообщением для получения более подробной информации.

однако, как качественная мера, мы можем вычесть это изображение из исходного изображения и посмотреть, что осталось:

imshow(rgb2gray(abs(double(im) - double(im_final_final))));

получаем:

enter image description here

Так выглядит например, оси и текст удаляются нормально, но на графике есть некоторые следы, которые мы не захватили из исходного изображения, и это имеет смысл. Все это связано с правильными порогами, которые вы хотите выбрать, чтобы получить данные графика. Есть некоторые проблемные места в начале графика, и это, вероятно, связано с морфологической обработкой, которую я сделал. Это изображение, которое вы предоставили, довольно сложно с шумом квантования, поэтому будет очень сложно получить идеальный результат. Кроме того, эти пороги, к сожалению, все эвристические, поэтому играйте с порогами, пока не получите что-то, что согласуется с вами.

удачи!


вот вариация на решение@rayryeng для извлечения синего сигнала:

%// retrieve picture
imgRGB = imread('http://i.stack.imgur.com/cFOSp.png');

%// detect axis lines and labels
imgHSV = rgb2hsv(imgRGB);
BW = (imgHSV(:,:,3) < 1);
BW = imclose(imclose(BW, strel('line',40,0)), strel('line',10,90));

%// clear those masked pixels by setting them to background white color
imgRGB2 = imgRGB;
imgRGB2(repmat(BW,[1 1 3])) = 255;

%// show extracted signal
imshow(imgRGB2)

extracted_signal

чтобы получить лучший вид, вот обнаруженная маска, наложенная поверх исходного изображения (я использую imoverlay функция из обмена файлами):

figure
imshow(imoverlay(imgRGB, BW, uint8([255,0,0])))

overlayed_mask


вот код для этого:

rgbImage = imread('ecg.png');

redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);

black = ~redChannel&~greenChannel&~blueChannel;

redChannel(black) = 255;
greenChannel(black) = 255;
blueChannel(black) = 255;

rgbImageOut = cat(3, redChannel, greenChannel, blueChannel);

imshow(rgbImageOut);

black область, содержащая черные пиксели. Эти пиксели имеют значение белого цвета в каждом цветовом канале.

в вашем коде вы используете порог и изображение в оттенках серого, поэтому, конечно, у вас есть гораздо большая площадь пикселей, которая установлена на белый resp. красный цвет. В этом коде только пиксель, который не содержит абсолютно никакого красного, зеленого и синего, установлен на белый.

следующий код делает то же самое с порогом для каждого цвета канал:

rgbImage = imread('ecg.png');

redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);

black = (redChannel<150)&(greenChannel<150)&(blueChannel<150);

redChannel(black) = 255;
greenChannel(black) = 255;
blueChannel(black) = 255;

rgbImageOut = cat(3, redChannel, greenChannel, blueChannel);

imshow(rgbImageOut);