How to segment a region in matlab - matlab

I want to segment a region from an image in MATLAB and display it in a different image file.
I have tried segmenting it but failed. I want to segment the region from 200:400(i.e. only the regions those are yellow and green)
I = imread('Intensity1.jpg');
imshow(I)
hold on
mask = false(size(I));
mask(200:400) = true;
visboundaries(mask,'Color','b');

Related

Finding area in image with maximum variation of pixels

I am struggling with some algorithm to extract the region from an image which has the maximum change in pixels. I got the following image after preprocessing.
I did following steps of pre-processing
x = imread('test2.jpg');
gray_x = rgb2gray(x);
I = medfilt2(gray_x,[3 3]);
gray_x = I;
%%
canny_x = edge(gray_x,'canny',0.3);
figure,imshow(canny_x);
%%
s = strel('disk',3);
si = imdilate(canny_x,s);
%figure5
figure; imshow(si);
se = imerode(canny_x,s);title('dilation');
%figure6
figure; imshow(se);title('Erodsion');
I = imsubtract(si,se);
%figure7
figure; imshow(I);
Basically what I am struggling for, is to make weapon detection system using Image processing. I want to localize possible area's to be weapon so that I could feed them to my classifier to identify if it is a weapon or not. Any suggestions? Thank you
A possible solution could be:
Find corner points in the image (Harris corner points, etc)
Set value of all the corner points to white while remaining image will be black
Take a rectangular window and traverse it over the whole image
sum all the white pixels in that rectangular window
select that region whose sum is maximum of all regions

Issue regarding detection of red and green colour using Matlab and Arduino [duplicate]

This question already has answers here:
How can I convert an RGB image to grayscale but keep one color?
(3 answers)
Closed 5 years ago.
I'm working on a smartcar project in which on detecting red color the car should stop and on detecting green color it should start running. I am using Matlab for color detection and Arduino to run the car. But the problem is I m not able to detect the green color, the code only detect red color and stop the car. I am not able to figure out the problem.
My code is:
vid = videoinput('winvideo',1 ,'YUY2_320x240');
s=serial('COM9','BAUD',9600);
fopen(s); %open serial port
set(vid, 'FramesPerTrigger', Inf);
set(vid, 'ReturnedColorspace', 'rgb')
vid.FrameGrabInterval = 10;
start(vid)
%set a loop that stop after 100 frames of aquisition
for i=1:100
IMRED = getsnapshot(vid); % get the snapshot of the current frame
diff_im = imsubtract(IMRED(:,:,1), rgb2gray(IMRED)); % subtract red component from the grayscale image to extract the red component in image.
gr=graythresh(diff_im);
diff_im1 = imsubtract(IMRED(:,:,2), rgb2gray(IMRED)); %subtract green component from the grayscale image to extract the green component in image.
gr1=graythresh(diff_im1);
diff_im = medfilt2(diff_im, [3 3]); % median filter to filter the noise.
diff_im1 = medfilt2(diff_im1, [3 3]);
% convert the resulting grayscale image into a binary image.
diff_im = im2bw(diff_im,.18);
diff_im1 = im2bw(diff_im1,.05);
% Remove all those pixels less than 300px
diff_im = bwareaopen(diff_im,300);
diff_im1 = bwareaopen(diff_im1,300);
% Label all the connected components in the image
[bw bw1] = bwlabel(diff_im, 8);
[L bw2] = bwlabel(diff_im1, 8);
if (bw1<=0 && bw2 <=0) % if no color detected run forward
fprintf(s,100);
elseif (bw1>=1) % if red detected stop the car
while (bw1>=1);
fprintf(s,101);
end
while(~(bw2>=1)) % start the car if green detected
fprintf(s,101);
end
fprintf(s,100);
if (bw2>=1)
fprintf(s,100);
else
fprintf(s,101);
end
else
fprintf(s,100);
end
imshow( IMRED )
hold on
hold off
end
stop(vid);
flushdata(vid);
delete(vid);
clear vid;
fclose(s);
clear all;
clc
I'm getting such output:
I guess that you are trying to find the pixels that have high green values,
I tried that in the past and it didn't work because of the difficulty of deciding the threshold under changing lighting and exposure conditions.
Instead, try converting the rgb values to hue, saturation and lightness (HSL) or HSV; and then see if given pixel's hue is close to the hue of green. That has worked for me as it ignores saturation and lightness of the pixel, the two values that can change wildly.
https://en.wikipedia.org/wiki/HSL_and_HSV
and
https://uk.mathworks.com/help/matlab/ref/rgb2hsv.html
also note, that for some cheap cameras, high intensity green might not look like green at all on the screen. You might need to adjust the camera's exposure manually to get a correct read-out of the hue.

How to plot boundary and centroids on video frames called inside step() function

I am calling some images inside a for loop and then doing some processing on those images. After that, I am using the step function to display those frames and their masks inside a video player. How can I add a boundary to an object inside the mask image? Also, how can I make the boundary thicker and plot the centroids of each blob in the mask in the mask image? Below is the rough sketch of the code.
videoPlayer = vision.VideoPlayer();
maskPlayer = vision.VideoPlayer();
for ii = 1:nfiles
filenameii = [............]
frame= imread(filenameii);
mask = dOB(frame,BackgroundImg);
% some processing on the images
mask= bwareaopen(mask,27);
boundaries = bwboundaries(mask,'noholes');
B=boundaries{1};
Centroid = regionprops(mask,'centroid');
Centroids = cat(1, Centroid.Centroid);
plot(B(:,2),B(:,1),'g','LineWidth',3);
plot(Centroids(:,1), Centroids(:,2), 'r+', 'MarkerSize', 10); step(videoPlayer,frame);
step(maskPlayer, mask);
P.S: I know how to display it on a figure using hold on but I would like this done directly on the image before displaying it in the video player. Any guidance would be appreciated.
Simply paint the pixels on the mask first before displaying it in the video player. What you have does work, but it will plot the boundary inside the figure for the mask player. Therefore, take your boundaries that you detected from bwboundaries, create linear indices from these coordinates and set the values in your image to white. What may be even simpler is to take your mask that you detected and use bwperim to automatically produce a mask that contains the boundaries of the blobs. I also see that you are filling in the holes of the mask, so you can use imfill directly on the output of your post-processing so that it gives you an image instead of coordinates. You would then use this mask to directly index into your image and set the coordinates of the boundaries of the blob to your desired colour. If you desire to make the perimeter thicker, a simple image dilation with imdilate using the appropriately sized square structuring element will help. Simply define the size of the neighbourhood of this structuring element to be the thickness of the perimeter that you desire. Finally, if you want to insert the centroids into the mask and since you have the MATLAB Computer Vision System Toolbox, use the insertMarker function so that you can use a set of points for each centroid and put them directly in the image. However, you must be sure to change the mask from a logical to a data type more suitable for images. uint8 should work. Therefore, cast the image to this type then multiply all nonzero values by 255 to ensure the white colours are maintained in the mask. With insertMarker, you want to insert red pluses with a size of 10 so we need to make sure we call insertMarker to reflect that. Also, because you want to have a colour image you will have to make your mask artificially colour and to do this painting individually for each plane for the colour that you want. Since you want green, this corresponds to the RGB value of (0,255,0).
Therefore, I have modified your code so that it does this. In addition, I've calculated the centroids of the filled mask instead of the original. We wouldn't want to falsely report the centroids of objects with gaps... unless that's what you're aiming for, but let's assume you're not:
videoPlayer = vision.VideoPlayer();
maskPlayer = vision.VideoPlayer();
% New - Specify colour you want
clr = [0 255 0]; % Default is green
% New - Define thickness of the boundaries in pixels.
thickness = 3;
% New - Create structuring element
se = strel('square', thickness);
for ii = 1:nfiles
filenameii = [............]
frame = imread(filenameii);
mask = dOB(frame, BackgroundImg);
% some processing on the images
mask = bwareaopen(mask,27);
%boundaries = bwboundaries(mask,'noholes');
%B=boundaries{1};
% New code - fill in the holes
mask = imfill(mask, 'holes');
Centroid = regionprops(mask,'centroid');
% New code - Create a boundary mask
mask_p = bwperim(mask, 8);
% New code - Make the boundaries thicker
mask_p = imdilate(mask_p, se);
% New code - create a colour image out of the mask
[red, green, blue] = deal(255*uint8(mask));
% Paint the perimeter of the blobs in the desired colour
red(mask_p) = clr(1); green(mask_p) = clr(2); blue(mask_p) = clr(3);
Centroids = cat(1, Centroid.Centroid);
%plot(B(:,2),B(:,1),'g','LineWidth',3);
%plot(Centroids(:,1), Centroids(:,2), 'r+', 'MarkerSize', 10);
% New - Make mask into RGB image for marker painting and to
% show to the user
mask_p = cat(3, red, green, blue);
% New - Insert the centroids directly in the mask image
mask_p = insertMarker(mask_p, Centroids, '+', 'color', 'r', 'size', 10);
step(videoPlayer, frame);
% New - Show new mask in the player
step(maskPlayer, mask_p);
end

MATLAB: Display image inside circle

As part of a circle recognition program, I have a background image with a geometrical circle with known coordinates and radius. I want the inside part of the circle filled by an image and the outside left alone. My best idea is some sort of circular mask, but I am not sure this is the best approach. Any suggestions?
X = imread('X.jpg'); % Background image jpg
Y = imread('Y.jpg'); % Filling image jpg
cent = [100,100]; % Center of circle
rad = 20; % Circle radius
% Fill circle ?
...
I have not provided the extended code, due to confidentiality.
I think the hard part was done by whomever authored this: http://matlab.wikia.com/wiki/FAQ#How_do_I_create_a_circle.3F
Assumptions:
I'm assuming you're not going to specify points that are out of range of the image (i.e. I'm not adding validation here).
I use the background image to relate the "center" of your circle to the coordinates.
I'm assuming radius is in pixels.
I didn't create a background image with a circle of known radius because I don't think that's necessary to create the filling effect you're looking for (unless I'm missing something).
Code:
X = imread('rdel_x.png'); % Background image jpg (I used a random image but this can be your blank + geometric circle)
Y = imread('rdel_y.png'); % Filling image jpg
cent = [100,150]; % Center of circle
rad = 70; % Circle radius
% make a mesh grid to provide coords for the circle (mask)
% taken from http://matlab.wikia.com/wiki/FAQ#How_do_I_create_a_circle.3F
[columnsInImage rowsInImage] = meshgrid(1:size(X,2), 1:size(X,1));
% circle points in pixels:
circlePixels = (rowsInImage - cent(1)).^2 ...
+ (columnsInImage - cent(2)).^2 <= rad.^2;
circlePixels3d=repmat(circlePixels,[1 1 3]); % turn into 3 channel (assuming X and Y are RGB)
X((circlePixels3d)) = Y((circlePixels3d)); % assign the filling image pixels to the background image for pixels where it's the desired circle
imagesc(X);
axis image off
Result: from left to right, background image, filling image, result from above code.
Edit: you might not even need the background image if everything is encapsulated in your coordinates. e.g. try appending this to the above code...
Z=zeros(size(X),'uint8'); % same size as your background
Z(circlePixels3d) = Y(circlePixels3d);
figure; % new fig
imagesc(Z);
axis image off

Set pixels on screen efficiently

I am using WindowAPI (http://www.mathworks.com/matlabcentral/fileexchange/31437) to show a black full screen in matlab.
When drawing on screen, turns out drawing using line() and rectangle() functions is extremely slow.
How can I set values of pixels without going through matlab's mechanism? Getting the window's canvas for example would be great.
One way to imitate a "canvas" is by using a MATLAB image. The idea is to manually change its pixels and update the 'CData' of the plotted image.
Note that you can use an image with the same dimensions as your screen size (image pixels will correspond to screen pixels one-to-one), but updating it would be slower. The trick is to keep it small and let MATLAB map it to the entire fullscreen. That way the image can be thought of as having "fat" pixels. Of course the resolution of the image is going to affect the size of the marker you draw.
To illustrate, consider the following implementation:
function draw_buffer()
%# paramters (image width/height and the indexed colormap)
IMG_W = 50; %# preferably same aspect ratio as your screen resolution
IMG_H = 32;
CMAP = [0 0 0 ; lines(7)]; %# first color is black background
%# create buffer (image of super-pixels)
%# bigger matrix gives better resolution, but slower to update
%# indexed image is faster to update than truecolor
img = ones(IMG_H,IMG_W);
%# create fullscreen figure
hFig = figure('Menu','none', 'Pointer','crosshair', 'DoubleBuffer','on');
WindowAPI(hFig, 'Position','full');
%# setup axis, and set the colormap
hAx = axes('Color','k', 'XLim',[0 IMG_W]+0.5, 'YLim',[0 IMG_H]+0.5, ...
'Units','normalized', 'Position',[0 0 1 1]);
colormap(hAx, CMAP)
%# display image (pixels are centered around xdata/ydata)
hImg = image('XData',1:IMG_W, 'YData',1:IMG_H, ...
'CData',img, 'CDataMapping','direct');
%# hook-up mouse button-down event
set(hFig, 'WindowButtonDownFcn',#mouseDown)
function mouseDown(o,e)
%# convert point from axes coordinates to image pixel coordinates
p = get(hAx,'CurrentPoint');
x = round(p(1,1)); y = round(p(1,2));
%# random index in colormap
clr = randi([2 size(CMAP,1)]); %# skip first color (black)
%# mark point inside buffer with specified color
img(y,x) = clr;
%# update image
set(hImg, 'CData',img)
drawnow
end
end