OpenCV MATLAB: How to draw a line having a particular Intensity profile? - matlab

Below is an arbitrary hand-drawn Intensity profile of a line in an image:
The task is to draw the line. The profile can be approximated to an arc of a circle or ellipse.
This I am doing for camera calibration. Since I do not have the actual industrial camera, I am trying to simulate the correction needed for calibration.
The question can be rephrased as I want pixel values which will follow a plot similar to the above. I want to do this using program (Preferably using opencv) and not manually enter these values because I have thousands of pixels in the line.
An algorithm/pseudo code will suffice. Also please note that I do not have any actual Intensity profile, otherwise I would have read those values.
When will you encounter such situation ?
Suppose you take a picture (assuming complete white) from a Camera, your object being placed on table, and camera just above it in vertical direction. The light coming on the center of the picture vertically downward from the camera will be stronger in intensity as compared to the light reflecting at the edges. You measure pixel values across any line in the Image, you will find intensity curve like shown above. Since I dont have camera for the time being, I want to emulate this situation. How to achieve this?

This is not exactly image processing, rather image generation... but anyways.
Since you want an arc, we still need three points on that arc, lets take the first, middle and last point (key characteristics in my opinion):
N = 100; % number of pixels
x1 = 1;
x2 = floor(N/2);
x3 = N;
y1 = 242;
y2 = 255;
y3 = 242;
and now draw a circle arc that contains these points.
This problem is already discussed here for matlab: http://www.mathworks.nl/matlabcentral/newsreader/view_thread/297070
x21 = x2-x1; y21 = y2-y1;
x31 = x3-x1; y31 = y3-y1;
h21 = x21^2+y21^2; h31 = x31^2+y31^2;
d = 2*(x21*y31-x31*y21);
a = x1+(h21*y31-h31*y21)/d; % circle center x
b = y1-(h21*x31-h31*x21)/d; % circle center y
r = sqrt(h21*h31*((x3-x2)^2+(y3-y2)^2))/abs(d); % circle radius
If you assume the middle value is always larger (and thus it's the upper part of the circle you'll have to plot), you can draw this with:
x = x1:x3;
y = b+sqrt(r^2-(x-a).^ 2);
plot(x,y);
you can adjust the visible window with
xlim([1 N]);
ylim([200 260]);
which gives me the following result:

Related

How to convert from the image coordinates to Cartesian coordinates

I have this 3D image generated from the simple code below.
% Input Image size
imageSizeY = 200;
imageSizeX = 120;
imageSizeZ = 100;
%# create coordinates
[rowsInImage, columnsInImage, pagesInImage] = meshgrid(1:imageSizeY, 1:imageSizeX, 1:imageSizeZ);
%# get coordinate array of vertices
vertexCoords = [rowsInImage(:), columnsInImage(:), pagesInImage(:)];
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
radius = 28;
%# calculate distance from center of the cube
sphereVoxels = (rowsInImage - centerY).^2 + (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2;
%# Now, display it using an isosurface and a patch
fv = isosurface(sphereVoxels,0);
patch(fv,'FaceColor',[0 0 .7],'EdgeColor',[0 0 1]); title('Binary volume of a sphere');
view(45,45);
axis equal;
grid on;
xlabel('x-axis [pixels]'); ylabel('y-axis [pixels]'); zlabel('z-axis [pixels]')
I have tried plotting the image with isosurface and some other volume visualization tools, but there remains quite a few surprises for me from the plots.
The code has been written to conform to the image coordinate system (eg. see: vertexCoords) which is a left-handed coordinate system I presume. Nonetheless, the image is displayed in the Cartesian (right-handed) coordinate system. I have tried to see this displayed as the figure below, but that’s simply not happening.
I am wondering if the visualization functions have been written to display the image the way they do.
Image coordinate system:
Going forward, there are other aspects of the code I am to write for example if I have an input image sphereVoxels as in above, in addition to visualizing it, I would want to find north, south east, west, top and bottom locations in the image, as well as number and count the coordinates of the vertices, plus more.
I foresee this would likely become confusing for me if I don’t stick to one coordinate system, and considering that the visualization tools predominantly use the right-hand coordinate system, I would want to stick with that from the onset. However, I really do not know how to go about this.
Right-hand coordinate system:
Any suggestions to get through this?
When you call meshgrid, the dimensions x and y axes are switched (contrary to ndgrid). For example, in your case, it means that rowsInImage is a [120x100x200] = [x,y,z] array and not a [100x120x200] = [y,x,z] array even if meshgrid was called with arguments in the y,x,z order. I would change those two lines to be in the classical x,y,z order :
[columnsInImage, rowsInImage, pagesInImage] = meshgrid(1:imageSizeX, 1:imageSizeY, 1:imageSizeZ);
vertexCoords = [columnsInImage(:), rowsInImage(:), pagesInImage(:)];

Quantifying pixels from a list of coordinates

I have a list of coordinates, which are generated from another program, and I have an image.
I'd like to load those coordinates (making circular regions of interest (ROIs) with a diameter of 3 pixels) onto my image, and extract the intensity of those pixels.
I can load/impose the coordinates on to the image by using;
imshow(file);
hold on
scatter(xCoords, yCoords, 'g')
But can not extract the intensity.
Can you guys point me in the right direction?
I am not sure what you mean by a circle with 3 pixels diameter since you are in a square grid (as mentioned by Ander Biguri). But you could use fspecial to create a disk filter and then normalize. Something like this:
r = 1.5; % for diameter = 3
h = fspecial('disk', r);
h = h/h(ceil(r),ceil(r));
You can use it as a mask to get the intensities at the given region of the image.
im = imread(file);
ROI = im(xCoord-1:xCoord+1; yCoord-1:yCoord+1);
I = ROI.*h;

Matlab: mask/create a circular roi knowing its origin point with a certain radius

Just a quick question. I've an image and I've extracted a certain point (feature), I know the coordinates of that point in every frame.
Say x1 and y1.
I need a circular ROI form that point on the image with a radius that I chose.
I tried impoly and roipoly - not sure how to use either of these when I know the point in the image.
Thanks
Since you know the coordinates of the center of the ROI along with the radius, you can modify a bit the code provided by #Jonas here to create a circular mask in a quite efficient way.
Example:
clc;clear
Im = imread('coins.png');
[rNum,cNum,~] = size(Im);
%// Define coordinates and radius
x1 = 60;
y1 = 100;
radius = 40;
%// Generate grid with binary mask representing the circle. Credit to Jonas for original code.
[xx,yy] = ndgrid((1:rNum)-y1,(1:cNum)-x1);
mask = (xx.^2 + yy.^2)<radius^2;
%// Mask the original image
Im(mask) = uint8(0);
imshow(Im)
Output:
EDIT
If you want to see only the outer edge of the ROI to see the center, add a logical condition with some tolerance for the radius of a smaller circle. Something like this:
mask = (xx.^2 + yy.^2)<radius^2 & (xx.^2 + yy.^2)>(radius-tol)^2;
With a tol of 2 it looks like this:

Rotating triangle in image - MATLAB

I'm writing a program for detecting basic shape in MATLAB.
when I detect the shape I evaluate its Orientation then I rotate the shape to make its Orientation Zero, then I can evaluate its Projection and specify what it is.
The problem is the MATLAB function: regionprops() doesn't evaluate Orientation of Triangle correctly.
I = zeros(256,256);
pos_triangle = [64 64 128 192 128 128];
Is = insertShape(I, 'FilledPolygon', pos_triangle);
imshow(Is)
original = Is;
originalBW = im2bw(original);
figure; imshow(originalBW);
S = regionprops(originalBW,'All');
bwr=imrotate(originalBW,S.Orientation);
S2 = regionprops(bwr,'Centroid','Orientation');
figure;imshow(bwr);
I use imrotate fnc for rotating image, I don't have problem with rotation, imrotate is working well. the problem is in calculating the Orientation [using 'regionprps()' fnc] of the image! for example:I want to turn the triangle from this position
http://postimg.org/image/4un4sc7pn/
Orentation value: -28.9621
So I rotate it 28.9621 degree to change its postion to this
http://postimg.org/image/x68opdrm3/
but the output is this:
http://postimg.org/image/yf15or8y3/
using their Orientation (or other possible property of image)
an other example: changing the position from Up-Left 2nd triangle to Up-Left 1st triangle
Here is a way to work it out. Notice that:
1) I don't have the Computer Vision System Toolbox so I can't use insertShape; instead I used the fill function to create the triangle in the image and then getframe to obtain the actual image. I guess it comes down to the same than using insertShape.
2) I used the 'FilledArea' property of regionprops to detect the triangular shape. That's easy when there is a single shape, but if there were many of them you would have to modify a bit the code.
3) I performed a rotation equal to -1* the orientation given by regionprops to bring it back to 0. You can of course change it. The rotated image is bigger to account for the rotation.
Here is the code:
clear
clc
close all
I = zeros(256,256);
pos_triangle = [64 64 128 192 128 128];
xt = [64 128 128];
yt = [64 192 128];
%// Since I don't have the Computer Vision System Toolbox I use 'fill'.
%//Is = insertShape(I, 'FilledPolygon', pos_triangle);
imshow(I)
hold on
fill(xt,yt,'w')
hold off
The original triangle:
%// Create image using getframe.
hFrame = getframe(gca);
original = hFrame.cdata;
originalBW = im2bw(original(:,:,1));
%// Remove border of the image.
originalBW = imclearborder(originalBW);
figure;
imshow(originalBW);
S = regionprops(originalBW,'FilledArea','Orientation');
%// Find region filled with the most pixels: that's the shape.
[a,b] =max([S.FilledArea]);
%// Get corresponding orientation
Orientation = S(b).Orientation;
%// Rotate by the inverse of the orientation; I'm not sur that's what you
%// want but it looks OK.
bwr=imrotate(originalBW,-1*Orientation);
S2 = regionprops(bwr,'Centroid','Orientation');
figure;imshow(bwr);
The rotated triangle, which looks like its orientation is 0.:
Hope that helps!
I'm not an expert in image processing but to achieve rotation is not hard. The only thing you need to know the center of your image. In Matlab, the center of an image in the upper left corner. To rotate an object around the center, you need to multiply every point by the rotation matrix. Let's rotate the triangle around the center of the image.
clear
clc
close all
I = zeros(256,256);
pos_triangle = [64 64 128 192 128 128];
xt = [64 128 128];
yt = [64 192 128];
a = deg2rad(20);
R = [cos(a) -sin(a);
sin(a) cos(a)];
p1 = R*[64; 64]
p2 = R*[128; 192]
p3 = R*[128; 128]
% the rotated points
x1 = [p1(1) p2(1) p3(1)];
y1 = [p1(2) p2(2) p3(2)];
imshow(I)
hold on
fill(x1,y1,'r')
fill(xt,yt,'w')
hold off
The result is now
If you would like to rotate it around itself, then you need to translate the center of the image to the center of the triangle. This is not a complete solution but I hope it helps.

How to measure the rotation of a image in MATLAB?

I have two images. One is the original, and the another is rotated.
Now, I need to discover the angle that the image was rotated. Until now, I thought about discovering the centroids of each color (as every image I will use has squares with colors in it) and use it to discover how much the image was rotated, but I failed.
I'm using this to discover the centroids and the color in the higher square in the image:
i = rgb2gray(img);
bw = im2bw(i,0.01);
s = regionprops(bw,'Centroid');
centroids = cat(1, s.Centroid);
colors = impixel(img,centroids(1),centroids(2));
top = max(centroids);
topcolor = impixel(img,top(1),top(2));
You can detect the corners of one of the colored rectangles in both the image and the rotated version, and use these as control points to infer the transformation between the two images (like in image registration) using the CP2TFORM function. We can then compute the angle of rotation from the affine transformation matrix:
Here is an example code:
%# read first image (indexed color image)
[I1 map1] = imread('http://i.stack.imgur.com/LwuW3.png');
%# constructed rotated image
deg = -15;
I2 = imrotate(I1, deg, 'bilinear', 'crop');
%# find blue rectangle
BW1 = (I1==2);
BW2 = imrotate(BW1, deg, 'bilinear', 'crop');
%# detect corners in both
p1 = corner(BW1, 'QualityLevel',0.5);
p2 = corner(BW2, 'QualityLevel',0.5);
%# sort corners coordinates in a consistent way (counter-clockwise)
p1 = sortrows(p1,[2 1]);
p2 = sortrows(p2,[2 1]);
idx = convhull(p1(:,1), p1(:,2)); p1 = p1(idx(1:end-1),:);
idx = convhull(p2(:,1), p2(:,2)); p2 = p2(idx(1:end-1),:);
%# make sure we have the same number of corner points
sz = min(size(p1,1),size(p2,1));
p1 = p1(1:sz,:); p2 = p2(1:sz,:);
%# infer transformation from corner points
t = cp2tform(p2,p1,'nonreflective similarity'); %# 'affine'
%# rotate image to match the other
II2 = imtransform(I2, t, 'XData',[1 size(I1,2)], 'YData',[1 size(I1,1)]);
%# recover affine transformation params (translation, rotation, scale)
ss = t.tdata.Tinv(2,1);
sc = t.tdata.Tinv(1,1);
tx = t.tdata.Tinv(3,1);
ty = t.tdata.Tinv(3,2);
translation = [tx ty];
scale = sqrt(ss*ss + sc*sc);
rotation = atan2(ss,sc)*180/pi;
%# plot the results
subplot(311), imshow(I1,map1), title('I1')
hold on, plot(p1(:,1),p1(:,2),'go')
subplot(312), imshow(I2,map1), title('I2')
hold on, plot(p2(:,1),p2(:,2),'go')
subplot(313), imshow(II2,map1)
title(sprintf('recovered angle = %g',rotation))
If you can identify a color corresponding to only one component it is easier to:
Calculate the centroids for each image
Calculate the mean of the centroids (in x and y) for each image. This is the "center" of each image
Get the red component color centroid (in your example) for each image
Subtract the mean of the centroids for each image from the red component color centroid for each image
Calculate the ArcTan2 for each of the vectors calculated in 4), and subtract the angles. That is your result.
If you have more than one figure of each color, you need to calculate all possible combinations for the rotation and then select the one that is compatible with the other possible rotations.
I could post the code in Mathematica, if you think it is useful.
I would take a variant to the above mentioned approach:
% Crude binarization method to knock out background and retain foreground
% features. Note one looses the cube in the middle
im = im > 1
Then I would get the 2D autocorrelation:
acf = normxcorr2(im, im);
From this result, one can easily detect the peaks, and as rotation carries into the autocorrelation function (ACF) domain, one can ascertain the rotation by matching the peaks between the original ACF and the ACF from the rotated image, for example using the so-called Hungarian algorithm.