image - poner - Para convertir solo el color negro a blanco en Matlab
imagen binaria matlab (4)
Conozco este hilo sobre la conversión simultánea de color negro a blanco y blanco a negro. Me gustaría convertir solo negro a blanco. Conozco este hilo acerca de hacer esto, lo que estoy preguntando, pero no entiendo qué va mal.
Imagen
Código
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);
Lo que da
Donde parece haber algo mal en el canal de color rojo. El color Negro es justo (0,0,0) en RGB, por lo que su eliminación debería significar convertir cada píxel (0,0,0) en blanco (255,255,255). Haciendo esta idea con
redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;
Da
Así que debo haber entendido mal algo en Matlab. El color azul no debería tener ningún negro. Entonces esta última imagen es extraña.
¿Cómo se puede convertir solo el color negro en blanco? Quiero mantener el color azul del ECG.
Aquí hay un código para esto:
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
es el área que contiene los píxeles negros. Estos píxeles se configuran en blanco en cada canal de color.
En tu código, utilizas un umbral y una imagen en escala de grises, así que por supuesto tienes un área de píxeles mucho mayor que está configurada en resp blanco. color rojo. En este código, solo los píxeles que contienen absolutamente ningún rojo, verde y azul se ponen blancos.
El siguiente código hace lo mismo con un umbral para cada canal de color:
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);
Si lo entiendo correctamente, quiere extraer el trazado azul de ECG mientras quita el texto y los ejes. La mejor manera de hacerlo sería examinar el espacio de color HSV de la imagen. El espacio de color HSV es ideal para discernir colores al igual que los humanos. Podemos ver claramente que hay dos colores distintos en la imagen.
Podemos convertir la imagen a HSV usando rgb2hsv
y podemos examinar los componentes por separado. El componente de tono representa el color dominante del píxel, la saturación denota la pureza o cuánta luz blanca hay en el píxel y el valor representa la intensidad o la fuerza del píxel.
Intenta visualizar cada canal haciendo:
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'');
Hmm ... bueno, el tono y la saturación no nos ayudan para nada. Nos dice que el color y la saturación dominantes son los mismos ... pero lo que los distingue es el valor . Si echas un vistazo a la imagen de la derecha, podemos diferenciarlos por la fuerza del color en sí. Entonces, lo que nos dice es que los píxeles "negros" son en realidad azules pero casi no tienen ninguna fuerza asociada.
De hecho, podemos usar esto para nuestro beneficio. Todos los píxeles cuyos valores están por encima de un cierto valor son los valores que queremos conservar.
Intenta establecer un umbral ... algo así como 0.75
. El rango dinámico de MATLAB de los valores HSV es de [0-1]
, entonces:
mask = hsv(:,:,3) > 0.75;
Cuando establecemos el umbral del componente de valor, esto es lo que obtenemos:
Obviamente hay un poco de ruido de cuantificación ... especialmente alrededor de los ejes y la fuente. Lo que voy a hacer a continuación es realizar una erosión morfológica para poder eliminar el ruido de cuantificación que está alrededor de cada uno de los números y los ejes. Voy a hacer que sea la máscara un poco grande para asegurarme de que elimine este ruido. Usando la caja de herramientas de procesamiento de imágenes:
se = strel(''square'', 5);
mask_erode = imerode(mask, se);
Obtenemos esto:
Genial, entonces lo que voy a hacer ahora es hacer una copia de tu imagen original, luego establecer cualquier píxel que sea negro desde la máscara que derivé (arriba) a blanco en la imagen final. Todos los demás píxeles deben permanecer intactos. De esta forma, podemos eliminar cualquier texto y los ejes que se vean en su imagen:
im_final = im;
mask_final = repmat(mask_erode, [1 1 3]);
im_final(~mask_final) = 255;
Necesito replicar la máscara en la tercera dimensión porque esta es una imagen en color y necesito establecer cada canal a 255 simultáneamente en las mismas ubicaciones espaciales.
Cuando hago eso, esto es lo que obtengo:
Ahora notará que hay lagunas en el gráfico ... que es de esperar debido al ruido de cuantificación. Podemos hacer algo más mediante la conversión de esta imagen a escala de grises y el umbral de la imagen, y luego llenar uniendo los bordes mediante una dilatación morfológica. Esto es seguro porque ya hemos eliminado los ejes y el texto. Entonces podemos usar esto como una máscara para indexar en la imagen original para obtener nuestro gráfico final.
Algo como esto:
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);
Limpio la imagen anterior que obtuvimos sin el texto y los ejes después de convertirla a escala de grises, y luego realizo la dilatación con un elemento de estructuración de línea que es de 90 grados para conectar esas líneas que fueron desconectadas originalmente. Esta imagen con umbral contendrá los píxeles que, en última instancia, necesitamos muestrear de la imagen original para que podamos obtener los datos del gráfico que necesitamos.
Luego tomo esta máscara, la replico, hago una imagen completamente blanca y luego tomo muestras de la imagen original y coloco las ubicaciones que quiero de la imagen original en la imagen blanca.
Esta es nuestra imagen final:
¡Muy agradable! Tuve que hacer todo el procesamiento de la imagen porque básicamente tu imagen tiene un ruido de cuantificación para empezar, así que será un poco más difícil obtener la gráfica por completo. Ander Biguri en su respuesta explicó con más detalle sobre el ruido de cuantificación del color, así que sin dudas echa un vistazo a su publicación para obtener más detalles.
Sin embargo, como medida cualitativa, podemos restar esta imagen de la imagen original y ver qué queda:
imshow(rgb2gray(abs(double(im) - double(im_final_final))));
Obtenemos:
Así que parece que los ejes y el texto se eliminan bien, pero hay algunos rastros en el gráfico que no captamos de la imagen original y eso tiene sentido. Todo tiene que ver con los umbrales adecuados que desea seleccionar para obtener los datos del gráfico. Hay algunos puntos problemáticos cerca del comienzo del gráfico, y eso probablemente se deba al procesamiento morfológico que hice. Esta imagen que proporcionó es bastante complicada con el ruido de cuantificación, por lo que será muy difícil obtener un resultado perfecto. Además, estos umbrales, lamentablemente, son heurísticos, así que juegue con los umbrales hasta que obtenga algo que esté de acuerdo con usted.
¡Buena suerte!
¿Cuál es el problema?
Desea detectar todas las partes negras de la imagen, pero en realidad no son negras
Ejemplo:
Tu idea (o tu código):
Binarize primero la imagen, seleccionando los píxeles que SON algo contra los píxeles que no lo son. En resumen, lo haces: if pixel>level; pixel is something
if pixel>level; pixel is something
¡Por lo tanto, hay un pequeño error que tienes aquí! cuando escribes
% Make the black parts pure red.
debería leer
% Make every pixel that is something (not background) pure red.
Por lo tanto, cuando lo haces
redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;
Tú lo estás haciendo
% Make every pixel that is something (not background) white
% (or what it is the same in this case, delete them).
Por lo tanto, lo que debe obtener es una imagen completamente blanca. La imagen no es completamente blanca porque ha habido algunos píxeles que fueron etiquetados como "no algo, parte del fondo" por el valor del level
, en el caso de su imagen alrededor de 0.6.
Una solución que podría pensarse es configurar manualmente el nivel en 0.05 o similar, por lo que solo se seleccionarán los píxeles negros en la retención de gris a binario. Pero esto no funcionará al 100%, como puede ver, las cifras tienen valores muy "no negros".
¿Cómo trataría de resolver el problema?
Intentaría encontrar el color que desea, extraer solo ese color de la imagen y luego eliminar los valores atípicos.
Extraiga azul usando HSV (creo que le contesté en otro lugar cómo usar 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)
Una vez aquí, nos gustaría obtener la parte azul más grande, y esa sería nuestra señal. Por lo tanto, el mejor enfoque parece primero binarizar la imagen tomando todos los píxeles azules
% Binarize image, getting all the pixels that are "blue"
bw=im2bw(rgb2gray(I2),0.9999);
Y luego, usando bwlabel
, etiquete todas las "islas" de píxeles independientes.
% Label each "blob"
lbl=bwlabel(~bw);
La etiqueta más repetida será la señal. Entonces lo encontramos y separamos el fondo de la señal usando esa etiqueta.
% 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;
Aquí hay un diagrama con la señal, el fondo y la diferencia (usando la misma ecuación que @rayryang utilizada)
Aquí hay una variación de la solución de @rayryeng para extraer la señal azul:
%// 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)
Para obtener una mejor vista, aquí está la máscara detectada superpuesta sobre la imagen original (estoy usando la función imoverlay
del Intercambio de archivos):
figure
imshow(imoverlay(imgRGB, BW, uint8([255,0,0])))