Remove black pixels from RGB image.

I know that variations of this question get asked a lot on here, but I haven't found a solution that works for my problem very well.
How do I remove the black border from the image above programmatically, but not by using imcrop!? I would prefer to find & remove all of the black pixels in the image, by effectively deleting that data--leaving me with a (yes) cropped image that contains only the color region of this image. My attempt is as follows:
% define scale bar:
firstFrame = read(vidObj,1);
imshow(firstFrame,'InitialMagnification',300);
title('Define the scale bar region:','FontSize',16);
scaleBar = drawrectangle('Color',[1 1 0]);
roi_Bar = scaleBar.Position;
% cropped and screwed:
I = imcrop(firstFrame, roi_Bar);
figure;
imshow(I);
% remove black border:
mask = (I(:, :, 1) == 0) & (I(:, :, 2) == 0) & (I(:, :, 3) == 0);
I(mask) = [];
figure;
imshow(I); % this returns a horrific result
Many thanks in advance!

2 comentarios

Mario Malic
Mario Malic el 15 de En. de 2021
Hi Luke,
I'll chip in my suggestions in here, while someone else with more knowledge comes by.
The border that you want to remove consists of different colors, not only of RGB [0, 0, 0], but RGB [0, 1, 0], and many other different colors. So, I guess the solution is to find all the colors that border consists of. Unfortunatelly, I can't help with this.
Thanks - this was a good information! Since all of the values might not be RGB [0 0 0], I could delete all the pixels around the border of the image (shown below), but if the user didn't select exactly the border of the scale bar correctly, this might crop part of the scale bar & lead to erroneous temperature readings.
% cropped and screwed:
I = imcrop(firstFrame, roi_Bar);
figure;
imshow(I);
figure;
bW = 3; % border width
iwant = I(bW:end-bW,bW:end-bW,:);
imshow(iwant);
It would be great if there was a robust edge detection method to use here. Thanks again for your suggestion!

Iniciar sesión para comentar.

 Respuesta aceptada

Image Analyst
Image Analyst el 16 de En. de 2021

1 voto

All black pixels cannot be removed since the image must remain rectangular. You can remove whole rows or whole columns, but not randomly scattered isolated groups of black pixels. With that colorbar image you have, you could delete everything up to and including the black outline of the colormap. Is that what you want to do?

7 comentarios

Luke G.
Luke G. el 16 de En. de 2021
Yes! Deleting everything up to and including the black outline would be great.
Image Analyst
Image Analyst el 16 de En. de 2021
Wait, the pseudocolored thermal picture you attached is nothing like the small color bar image inserted into the body of your message. So let me get this straight. You want just the color bar itself, without the black outline around it and without any other stuff in the scene - just the color bar alone, right? And do you want the color bar cropped out to be its own output image?
Luke G.
Luke G. el 16 de En. de 2021
All of that is correct! Thanks.
Since the colorbar is burned into the image at a constant location for the thermal images from that camera, you can determine that location, like with impixelinfo(), and then simply crop it out:
colorBarImage = rgbImage(row1:row2, column1:column2, :);
Yes, that's my current solution (code below).
img_scale = rgb2gray(imcrop(firstFrame, roi_Bar));
bW = 3; % border width
img_scale = img_scale(bW:end-bW,bW:end-bW,:); % trim border
img_scale = img_scale(:,1,:); % keep vertical strip
scaleRows = length(img_scale);
However, the border isn't necessarily fixed width: I'm designing this so that the user draws a rectangle over the scale bar in the image (using drawrectangle), however if the rectangle drawn by the user isn't precisely at the border of the scale bar, then removing a fix width border of pixels might leave some black pixels in the frame OR it might cut off part of the scale bar (more serious issue).
--
Stepping back from this^ problem, the larger problem is that I want to find the hottest point in each frame of infrared video & calculate the temperature based on a changing scale bar. Instead of the method above, I'm wondering if it makes sense to just analyze the grayscale image and find the hottest (i.e., "whitest") point in the grayscale region of interest. I've sketched some code for this (see below), but so far it's not picking up on the hottest region... I'm afraid a more accurate solution might require some statistics/probability. Thoughts? Suggestions?
%% Setup:
clc; close all; clear;
folder = pwd; fontSize = 14;
%% Get movie data:
% select .mp4 files:
uiwait(msgbox({'Select your video on the following page.'},'WELCOME','modal'));
mviFileName = uigetfile('*.mp4','Multiselect','off');
movieFullFileName = fullfile(folder, mviFileName);
% video object, pre-allocation:
vidObj = VideoReader(mviFileName);
numFrames = floor((vidObj.Duration)*(vidObj.FrameRate))-1;
tempData = cell(numFrames,1);
frameData = cell(numFrames,1);
frameDataText = cell(numFrames,1);
%% Set up for analysis:
prompt1 = sprintf('Use your mouse to outline the requested info on the next few plots.');
uiwait(msgbox(prompt1,'Instructions','modal'));
% define max & min temp read-outs:
firstFrame = read(vidObj,1);
imshow(firstFrame,'InitialMagnification',300);
title('Define lower scale limit:','FontSize',16);
T_lo = drawrectangle('Color',[1 1 0]);
roi_T_lo = T_lo.Position;
title('Define upper scale limit:','FontSize',16);
T_hi = drawrectangle('Color',[1 1 0]);
roi_T_hi = T_hi.Position;
% define region for analysis:
title('Select region for analysis:','FontSize',16)
find = drawrectangle('Color',[1 1 0]);
roi_find = find.Position;
close all
%% Analysis:
% preallocation:
T_hottest = zeros(1,numFrames);
t = zeros(1,numFrames);
hot_row = zeros(1,numFrames); hot_col = zeros(1,numFrames);
% execution:
for k = 1:numFrames
img = rgb2gray(imcrop(readFrame(vidObj),roi_find));
S = sum(img,3); %
[~,idx] = max(S(:));
[hot_row(k), hot_col(k)] = ind2sub(size(S),idx);
% scaling:
T_min = ocr(readFrame(vidObj),roi_T_lo); % obj. char. recognition
T_min = sscanf(T_min.Text,'%d')/10; % lower temp
T_max = ocr(readFrame(vidObj),roi_T_hi); % obj. char. recognition
T_max = sscanf(T_max.Text,'%d')/10; % upper temp
% ADD CODE: *if we get special characters, ask for help*
% calculating the max temp:
T_hottest(k) = T_min + ((T_max-T_min)/255)*img(hot_row(k),hot_col(k));
t(k) = vidObj.CurrentTime;
imshow(img,'InitialMagnification',300);
hold on; plot(hot_row(k),hot_col(k),'ro')
tite = sprintf('t = %.3f s',t(k)); title(tite);
txt = sprintf(' %.1f %cC',T_hottest(k),char(176));
hText = text(hot_row(k),hot_col(k),txt,'Color','red','FontSize',12);
drawnow
delete(hText);
end
Image Analyst
Image Analyst el 17 de En. de 2021
See my attached demo. Make the necessary adaptations.
But the best solution is to just get a thermal camera that outputs the temperature image. I think it's only the very cheapest FLIR model that gives you only a pseudocolored image. Pay a few bucks more and get one that has the image directly in degrees Celsius.
Luke G.
Luke G. el 17 de En. de 2021
Thanks Image Analyst! Appreciate the info & support.

Iniciar sesión para comentar.

Más respuestas (1)

Jeffrey Daniels
Jeffrey Daniels el 31 de En. de 2023

0 votos

img_2d = reshape(img,[numrows*numcols],3);
% Find the indices of the rows that are remove_color
remove_color = [0,0,0];
color_idx = ~ismember(img_2d,remove_color, 'rows');
% Replace remove_color with white
img_2d(color_idx) = [255,255,255];
img = reshape(img_2d,[numrows,numcols,3]);
% Remove the rows that are remove_color (Optional, if you really want to "remove" them", but as stated it will no longer be rectanglar. This only works if you want statistics on your colors.)
img_2d_nw = img_2d(~color_idx, :);

1 comentario

Improvements to make a better answer:
  • Format the code
  • Make the example complete enough that it can be demonstrated in the editor
  • Make sure the example does what you say it does
% a uint8 RGB image with black border
img = imread('peppers.png');
img = padarray(img,[10 10],0,'both');
imshow(img)
% get the size
[numrows,numcols,nchan,~] = size(img);
% reshape the image into a 3-column matrix
img_2d = reshape(img,numrows*numcols,3);
% Find the indices of the rows that are remove_color
remove_color = [0,0,0];
color_idx = ismember(img_2d,remove_color,'rows'); % select the correct region
% Either replace remove_color with a new color ...
new_color = [255 255 0]; % white would be invisible against the webpage background
img_2d(color_idx,:) = repmat(new_color,[nnz(color_idx) 1]); % make sure addressing works
img = reshape(img_2d,[numrows,numcols,3]);
imshow(img)
% ... or remove the rows that are remove_color
% (Optional, if you really want to "remove" them", but as stated it will no longer be rectanglar.
% This only works if you want statistics on your colors.)
img_2d_nw = img_2d(~color_idx, :);

Iniciar sesión para comentar.

Categorías

Más información sobre Image Processing Toolbox en Centro de ayuda y File Exchange.

Preguntada:

el 15 de En. de 2021

Comentada:

DGM
el 31 de En. de 2023

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by