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

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

Рисунок

введите описание изображения здесь

Код

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

Который дает

введите описание изображения здесь

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

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

Дает

введите описание изображения здесь

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

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


person Léo Léopold Hertz 준영    schedule 22.04.2015    source источник


Ответы (4)


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

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

Пример:

введите описание изображения здесь

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

Сначала вы преобразуете изображение в двоичную форму, выбирая пиксели, которые ЯВЛЯЮТСЯ чем-то, по сравнению с пикселями, которые не являются. Короче говоря, вы делаете: 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)

введите описание изображения здесь

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

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

введите описание изображения здесь

person Ander Biguri    schedule 22.04.2015
comment
Очень хорошо. Практически тот же подход, что и я, почти лол. +1. - person rayryeng; 22.04.2015
comment
Звучит неплохо. Можно было бы подумать о том, чтобы вручную установить уровень на 0,05 или аналогичный, так что только черные пиксели будут выбраны в сером для двоичной привязки. Вы имеете в виду с binary-Threshold-0.60 и уровень 0,05. Было бы неплохо иметь возможность приблизительно оценить неопределенность или количество потерянного сигнала с помощью Threshold-0.60 и уровня 0.05. И сравните это с порогом 0,75 с уровнем 0,05. Я считаю, что уровень 0,05 - хороший выбор. Я думаю, что изменяемый параметр - Порог. - person Léo Léopold Hertz 준영; 22.04.2015
comment
@Masi Level == gray2bw treshold в этом случае. Однако проверьте мой обновленный ответ, чтобы увидеть способ извлечения сигнала из сюжета. - person Ander Biguri; 23.04.2015
comment
Последнее изображение получено figure; imshow(rgb2gray(abs(double(rgbImage) - double(signal)))); здесь, как описано в ответе rayryeng, поэтому полученный сигнал удаляется из исходного рисунка RGB. - person Léo Léopold Hertz 준영; 23.04.2015
comment
Это кажется лучшим результатом, чем результат Райренга при осмотре. Теперь я думаю о том, чтобы качественно разработать какой-нибудь индикатор, чтобы оценить, насколько хорош ваш результат, особенно возле осей. Вроде по центру ложноположительных съемов нет, но могут быть по углам. - person Léo Léopold Hertz 준영; 23.04.2015
comment
Отличный результат! Я прошел через ложноположительные удаления. Я их не нашел. Всего в белом поле size(find(comp_image(25:446, 41:574) > 0)) удалено 2042 пикселя, с учетом поля в 1 черный пиксель вокруг него. Только по осям 2042 (= (422-1)*2 + (533-1)*2 + 5*9*2 + 7*4 + 5*3 + 4*2 + 3*1 - 7 - 1 ) белых пикселя. Ничего не удалено из фактического сигнала ЭКГ. Можешь подтвердить? - person Léo Léopold Hertz 준영; 23.04.2015
comment
@Masi Спасибо. Я не совсем понимаю, что ты имеешь в виду. Ложных срабатываний действительно мало (пиксели, которые выбираются как сигнал, когда они являются осями / фоном). Это пиксели, которые отсутствуют в левой и правой осях около 0-0,1. Похоже, их размер составляет около 10 пикселей, но единственный способ их сосчитать - это буквально пересчитать! - person Ander Biguri; 23.04.2015
comment
@AnderBiguri Да, я сделал это. Я также вычислил пиксели в центре, но ничего не нашел. Я посчитал все белые пиксели на картинке без текста. - person Léo Léopold Hertz 준영; 23.04.2015
comment
Объясните, пожалуйста, почему вы используете этот массив [1 1 3] здесь signal(repmat((lbl~=idxmax),[1 1 3]))=255;? Почему 3 на последок? Как прочитать всю строку? Вы наносите эти капли на карту таким образом, чтобы они не были видны в сигнале. - person Léo Léopold Hertz 준영; 29.04.2015
comment
Это проблема индексации. Всякий раз, когда требуется белый пиксель, вам нужно установить 3 канала (RGB) на 255, поэтому 3. Что означает Как читать всю строку? означает?. Я действительно выбираю не самые большие капли и устанавливаю для них белый цвет. @Masi - person Ander Biguri; 29.04.2015
comment
Я расширил эту задачу до проблемы с цветами здесь stackoverflow.com/q/29990133/54964 Обратите внимание также, что есть много щук и горизонтальные линии в данных, что также усложняет проблему. Ваше решение работает лучше всего из всех ответов здесь с такими данными, но недостаточно хорошо. - person Léo Léopold Hertz 준영; 01.05.2015
comment
@Masi плохо посмотри. Однако вы не должны выбирать ответ как принятый здесь! - person Ander Biguri; 02.05.2015

Если я вас правильно понял, вы хотите извлечь синий график ЭКГ, удалив текст и оси. Лучший способ сделать это - изучить цветовое пространство 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');

введите описание изображения здесь

Хм ... ну, оттенок и насыщенность нам совершенно не помогают. Он говорит нам, что доминирующий цвет и насыщенность одинаковы ... но их отличает значение. Если вы посмотрите на изображение справа, мы сможем отличить их друг от друга по силе самого цвета. Это говорит нам о том, что «черные» пиксели на самом деле синие, но с ними почти не связана сила.

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

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

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

Когда мы устанавливаем пороговое значение для компонента значения, мы получаем следующее:

введите описание изображения здесь

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

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

Получаем вот что:

введите описание изображения здесь

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

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

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

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

введите описание изображения здесь

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

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

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 градусов, чтобы соединить те линии, которые изначально были отключен. Это пороговое изображение будет содержать пиксели, которые нам в конечном итоге понадобятся для выборки из исходного изображения, чтобы мы могли получить нужные нам данные графика.

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

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

введите описание изображения здесь

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

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

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

Мы получили:

введите описание изображения здесь

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

Удачи!

person rayryeng    schedule 22.04.2015
comment
Можете ли вы приблизительно оценить, сколько информации теряется из сигнала при любом выборе порога? Th-0.60 и Th-0.75 кажутся примерно одинаковыми. На сколько очков вы потеряли больше от первого, чем от второго? - person Léo Léopold Hertz 준영; 22.04.2015
comment
@Masi - На этот вопрос сложно ответить. Ваше изображение уже подверглось шуму квантования, поэтому я не могу сказать, какая часть вашего исходного сигнала была там до шума и какая часть данных присутствует из-за шума квантования. Если вы пытаетесь использовать этот график для точности, то, вероятно, вам не следует этого делать. - person rayryeng; 22.04.2015
comment
@Masi - Однако, если вы хотите определить, сколько пикселей различаются в маске между 0.60 и 0.75, просто установите пороговое значение для обоих изображений с этим количеством и сохраните их в отдельных изображениях ... называемых I1 и I2, затем выполните abs(nnz(I1) - nnz(I2)), чтобы определить, сколько пикселей различаются между обоими изображениями. Оттуда вы можете определить, сколько процентных изменений произошло. - person rayryeng; 22.04.2015
comment
Как определяется переменная im_dilate? - person Léo Léopold Hertz 준영; 22.04.2015
comment
@ Маси - ой. извини, подожди - person rayryeng; 22.04.2015
comment
@Masi - Поехали. Прости. Я забыл выполнить расширение изображения. - person rayryeng; 22.04.2015
comment
Можете ли вы оценить, насколько эти пересечения осей с графиком влияют на ваш окончательный результат? dropbox.com/s/9injflk0iti6m3u/ECGexample1.pdf% 20copy.png? Dl = 0 - person Léo Léopold Hertz 준영; 22.04.2015
comment
@Masi - В этом прелесть цветового пространства HSV. Пересечения имеют компоненты значений, отличные от самих данных графика, поэтому, когда я установил пороговое значение для плоскости значений, мне удалось удалить эти оси. Взгляните на мою редакцию, где я действительно показал разницу между окончательным изображением и оригиналом. - person rayryeng; 22.04.2015
comment
Сигнал очень сильно теряется, и я хочу понять, почему. Различный выбор порога на это не сильно повлиял, чего я не понимаю. Исходные данные взяты из этого файла PDF: dropbox.com/s/ dvc2vz8k2r0th6n / ECGexample1.pdf? dl = 0 Это должно быть точно такое же изображение, что и в моем вопросе. - person Léo Léopold Hertz 준영; 22.04.2015
comment
Потеря этих пиков (показаны белым) на ЭКГ очень важны для приложения. Почему они теряются при обработке? Можно ли что-то изменить, чтобы они не терялись? Думаю, причиной может быть выбор линии под углом 90 градусов. Может быть установлен на 89 градусов или что-то еще. В сигнале ЭКГ должны быть разрешены пики. - person Léo Léopold Hertz 준영; 22.04.2015
comment
Хм ... не было бы разумнее просто обрезать изображение? Не могли бы вы просто указать интересующую вас область и просто удалить все остальное, кроме самих данных? - person rayryeng; 22.04.2015
comment
@Masi - попробую еще один элемент структурирования. Дай мне минутку. - person rayryeng; 22.04.2015
comment
Я начал придумывать новую цветовую карту при создании маски для шума квантования здесь stackoverflow.com/q/29806687/54964 - person Léo Léopold Hertz 준영; 22.04.2015
comment
Я собираюсь закончить редактирование своего вопроса, потому что похоже (я очень взволнован) мой ответ работает немного лучше, чем то, что делает замечательный райрен (ОМГОМГОМГ, это необычно!). Проверьте это @Masi - person Ander Biguri; 23.04.2015
comment
@AnderBiguri - lmao. Я приветствую время от времени ошибаться. Пожалуйста, позвольте мне увидеть ваши результаты :) - person rayryeng; 23.04.2015
comment
@rayryeng, извините, их публикация заняла немного времени. Там они! - person Ander Biguri; 23.04.2015
comment
@rayryeng: Я опаздываю, но в другом вопросе от OP я опубликовал аналогичное решение с улучшенными результатами. В основном я применяю две морфологические операции закрытия, используя горизонтальные и вертикальные линии в качестве структурирующего элемента. Ознакомьтесь с разделом извлечения синего сигнала ЭКГ из второй части этого ответа. - person Amro; 30.04.2015

Вот вариант решения @ 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)

extract_signal

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

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

overlayed_mask

person Amro    schedule 29.04.2015
comment
Я просмотрел набор сигналов ЭКГ и их частотно-временные соответствия, где также сила сигнала визуализирована цветами. Этот метод ломается в этом пространстве TF. Однако, похоже, он хорошо работает с единообразными сигналами ЭКГ. Позже я постараюсь предоставить некоторые данные об этих частных случаях. Сейчас я проверяю, работает ли этот метод во всех вариантах ЭКГ. Это должно происходить всякий раз, когда цветовая кодировка единообразна. - person Léo Léopold Hertz 준영; 01.05.2015

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

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 - это область, содержащая черные пиксели. Эти пиксели устанавливаются на белый цвет в каждом цветовом канале.

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

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

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);
person Thomas Sablik    schedule 22.04.2015
comment
Можете ли вы приблизительно оценить, сколько данных вы потеряете, если у вас установлен порог 240? Задача состоит в том, чтобы найти достаточно хороших данных с выбором порога. - person Léo Léopold Hertz 준영; 22.04.2015
comment
240-е изображение - это dropbox.com/s/pxl99xd8zd64xxt/ - person Léo Léopold Hertz 준영; 22.04.2015
comment
Что вы имеете в виду под потерянными данными? Поменяли пиксели синего графика? - person Thomas Sablik; 22.04.2015
comment
Я пробовал это с порогом для синего 250, и красный и зеленый каналы были удалены. Ни один пиксель графика не изменился. Никаких потерь данных. - person Thomas Sablik; 22.04.2015
comment
Фактически, данные теряются из-за порогового изменения синего цвета, вызванного квантованием шума из текста и оси, как описано в ответе Rayryeng. На синем графике видны пробелы. - person Léo Léopold Hertz 준영; 22.04.2015
comment
Ты прав. Я не сравнивал эту часть графика. Я сравнивал только раздел изображений (32: 438,48: 565, :). В этом разделе нет разницы. Строго говоря, график не изменился, потому что в этот момент графика не было. - person Thomas Sablik; 22.04.2015