Matlab - how to calculate image pixels shift - matlab

In Matlab, I have two similar images, but one has a pixels shift compare to the other. how can I calculate the the offset (amount of pixels) for axis x and y?
Image Center
Image Shift

The general problem is called image registration. You can use cross-correlation to find the subpixel image registration, for example by the function dftregistration on the file exchange.
To register the two images A and B within 0.1 pixels by specifying an upsampling parameter of 10
A=(imread("img1.png"));
B=(imread("img2.png"));
upsamplingfactor = 10;
output = dftregistration(fft2(A),fft2(B),upsamplingfactor );
disp(output),
0.2584 0.0000 75.5000 -85.5000
We get an image shifted by y=75.5 and x=-85.5 pixels with an uncertainty of 0.258 pixels. This can get more accurate if you process the image before to reduce noise via applying a threshold or blurring)

Related

Reduce number of pixels to obtain low-resolution image

I am trying to use different low resolution images for my work. Recently, I was reading the LOW RESOLUTION CONVOLUTIONAL NEURAL NETWORK FOR AUTOMATIC TARGET
RECOGNITION in which they didn't mentioned the way how they made the low resolution images.
Resolution adaptation for feature computation: To show the influence
of resolution on the performances of these image representations, we
focus on seven specific resolutions ranging from 200 × 200 to 10 × 10
pixels
Here is the example images from the paper.
Anyone please help me to implement this method in MATLAB?
Currently, I am using this way to make the Low resolution images:
img = im2double(imread('cameraman.tif'));
conv_mat = ones(6) / 36;
img_low = convn(img,conv_mat,'same');
figure, imshow(img), title('Original');
figure, imshow(img_low), title('Low Resolution')
You have a good start there. The convolution makes it so that each pixel contains the average of a 6x6 neighborhood. Now all that is left is to keep only one pixel in each 6x6 neighborhood. This pixel will have an average of the deleted information:
img = im2double(imread('cameraman.tif'));
conv_mat = ones(6) / 36;
img_low = convn(img,conv_mat,'same');
img_low = img_low(3:6:end,3:6:end)
figure, imshow(img), title('Original');
figure, imshow(img_low), title('Low Resolution')
The 3:6:end simply indicates which columns and which rows to keep. I start the subsampling at 3, to avoid the pixels that were averaged with the background.
Judging from the images you posted, they used this averaging method. Other alternatives are to take the max in the neighborhood (as is done in the max-pooling layers of a convolutional neural network), or simply subsample without any filtering (introduces aliasing, I don't recommend this method).

Making a sinusoidal curve in an image into a straight line in the output image

I have to make a sinusoidal curve in an image to output an equal straight line in the resulting image.
An example of input sinusoidal image:
What I think is one solution should be:
Placing down the origin of x and y coordinates at the start of the curve, so we will have y=0 at the starting point. Then points on the upper limit will be counted as such that y= y-(delta_y) and for lower limits, y=y+(delta_y)
So to make upper points a straight line, our resulting image will be:
O[x,y-delta_y]= I[x,y];
But how to calculate deltaY for each y on horizontal x axis (it is showing the distance of curve points from horizontal axis)
Another solution could be, to save all information of the curve in a variable and to plot it as a straight line, but how to do it?
Since the curve is blue we can use information from the blue and red channels to extract the curve. Simply subtraction of red channel from blue channel will highlight the curve:
a= imread('kCiTx.jpg');
D=a(:,:,3)-a(:,:,1);
In each column of the image position of the curve is index of the row that it's value is the maximum of that column
[~,im]=max(D);
so we can use row position to shift each column so to create a horizontal line. shifting each column potentially increases size of the image so it is required to increase size of the image by padding the image from top and bottom by the size of the original image so the padded image have the row size of 3 times of the original image and padding value is 255 or white color
pd = padarray(a,[size(a,1) 0 0], 255);
finally for each channel cirshift each column with value of im
for ch = 1:3
for col = 1: size(a,2)
pd(:,col,ch) = circshift(pd(:,col,ch),-im(col));
end
end
So the result will be created with this code:
a= imread('kCiTx.jpg');
D=a(:,:,3)-a(:,:,1);
%position of curve found
[~,im]=max(D);
%pad image
pd = padarray(a,[size(a,1) 0 0], 255);
%shift columns to create a flat curve
for ch = 1:3
for col = 1: size(a,2)
pd(:,col,ch) = circshift(pd(:,col,ch),-im(col));
end
end
figure,imshow(pd,[])
If you are sure you have a sinusoid in your initial image, rather than calculating piece-meal offsets, you may as well estimate the sinusoidal equation:
amplitude = (yMax - yMin)/2
offset = (yMax + yMin)/2
(xValley needs to be the valley immediately after xPeak, alternately you could do peak to peak, but it changes the equation, so this is the more compact version (ie you need to see less of the sinusoid))
frequencyScale = π / (xValley - xPeak)
frequencyShift = xFirstZeroCrossRising
If you are able to calculate all of those, this is then your equation:
y = offset + amplitude * sin(frequencyScale * (x + frequencyShift))
This equation should be all you need to store from one image to be able to shift any other image, it can also be used to generate your offsets to exactly cancel your sinusoid in your image.
All of these terms should be able to be estimated from the image with relatively little difficulty. If you can not figure out how to get any of the terms from the image, let me know and I will explain that one in particular.
If you are looking for some type of distance plot:
Take your first point on the curvy line and copy it into your output image, then measure the distance between that point and the next point on the (curvy) line. Use that distance to offset (from the first point) that next point into the output image only along the x axis. You may want to do it pixel by pixel, or grab clumps of pixels through averaging or jumping (as pixel by pixel will give you some weird digital noise)
If you want to be cleaner, you will want to set up a step size which was sufficiently small to approximately match the maximum sinusoidal curvature without too much error. Then, estimate the distance as stated above to set up bounds and then interpolate each pixel between the start and end point into the image averaging into bins based on approximate position. IE if a pixel from the original image would fall between two bins in the output image, you would split it and add its weighted parts to those two bins.

Subpixel edge detection for almost vertical edges

I want to detect edges (with sub-pixel accuracy) in images like the one displayed:
The resolution would be around 600 X 1000.
I came across a comment by Mark Ransom here, which mentions about edge detection algorithms for vertical edges. I haven't come across any yet. Will it be useful in my case (since the edge isn't strictly a straight line)? It will always be a vertical edge though. I want it to be accurate till 1/100th of a pixel at least. I also want to have access to these sub-pixel co-ordinate values.
I have tried "Accurate subpixel edge location" by Agustin Trujillo-Pino. But this does not give me a continuous edge.
Are there any other algorithms available? I will be using MATLAB for this.
I have attached another similar image which the algorithm has to work on:
Any inputs will be appreciated.
Thank you.
Edit:
I was wondering if I could do this:
Apply Canny / Sobel in MATLAB and get the edges of this image (note that it won't be a continuous line). Then, somehow interpolate this Sobel edges and get the co-ordinates in subpixel. Is it possible?
A simple approach would be to project your image vertically and fit the projected profile with an appropriate function.
Here is a try, with an atan shape:
% Load image
Img = double(imread('bQsu5.png'));
% Project
x = 1:size(Img,2);
y = mean(Img,1);
% Fit
f = fit(x', y', 'a+b*atan((x0-x)/w)', 'Startpoint', [150 50 10 150])
% Display
figure
hold on
plot(x, y);
plot(f);
legend('Projected profile', 'atan fit');
And the result:
I get x_0 = 149.6 pix for your first image.
However, I doubt you will be able to achieve a subpixel accuracy of 1/100th of pixel with those images, for several reasons:
As you can see on the profile, your whites are saturated (grey levels at 255). As you cut the real atan profile, the fit is biased. If you have control over the experiments, I suggest you do it again again with a smaller exposure time for instance.
There are not so many points on the transition, so there is not so many information on where the transition is. Typically, your resolution will be the square root of the width of the atan (or whatever shape you prefer). In you case this limits the subpixel resolution at 1/5th of a pixel, at best.
Finally, your edges are not stricly vertical, they are slightly titled. If you choose to use this projection method, to increase the accuracy you should look for a way to correct this tilt before projecting. This won't increase your accuracy by several orders of magnitude, though.
Best,
There is a problem with your image. At pixel level, it seems like there are four interlaced subimages (odd and even rows and columns). Look at this zoomed area close to the edge.
In order to avoid this artifact, I just have taken the even rows and columns of your image, and compute subpixel edges. And finally, I look for the best fitting straight line, using the function clsq whose code is in this page:
%load image
url='http://i.stack.imgur.com/bQsu5.png';
image = imread(url);
imageEvenEven = image(1:2:end,1:2:end);
imshow(imageEvenEven, 'InitialMagnification', 'fit');
% subpixel detection
threshold = 25;
edges = subpixelEdges(imageEvenEven, threshold);
visEdges(edges);
% compute fit line
A = [ones(size(edges.x)) edges.x edges.y];
[c n] = clsq(A,2);
y = [1,200];
x = -(n(2)*y+c) / n(1);
hold on;
plot(x,y,'g');
When executing this code, you can see the green line that best aproximate all the edge points. The line is given by the equation c + n(1)*x + n(2)*y = 0
Take into account that this image has been scaled by 1/2 when taking only even rows and columns, so the right coordinates must be scaled.
Besides, you can try with the other tree subimages (imageEvenOdd, imageOddEven and imageOddOdd) and combine the four straigh lines to obtain the best solution.

Decomposing an image into two frequency components using DCT?

I am a beginner in digital image processing field, recently I am working on a project where I have to decompose an image into two frequency components namely (low and high) using DCT. I searched a lot on web and I found that MATLAB has a built-in function for Discrete Cosine Transform which is used like this:
dct_img = dct2(img);
where img is input image and dct_img is resultant DCT of img.
Question
My question is, "How can I decompose the dct_img into two frequency components namely low and high frequency components".
As you've mentioned, dct2 and idct2 will do most of the job for you. The question that remains is then: What is high frequency and what is low frequency content? The coefficients after the 2 dimensional transform will actually represent two frequencies each (one in x- and one in y-direction). The following figure shows the bases for each coefficient in an 8x8 discrete cosine transform:
Therefore, that question of low vs. high can be answered in different ways. A common way, which is also used in the JPEG encoding, proceeds diagonally from zero-frequency downto the max as shown above. As we can see in the following example that is mostly motivated because natural images are largely located in the "top left" corner of "low" frequencies. It is certainly worth looking at the result of dct2 and play around with the actual choice of your regions for high and low.
In the following I'm dividing the spectrum diagonally and also plotting the DCT coefficients - in logarithmic scale because otherwise we would just see one big peak around (1,1). In the example I'm cutting far above half of the coefficients (adjustable with cutoff) we can see that the high-frequency part ("HF") still contains some relevant image information. If you set cutoff to 0 or below only noise of small amplitude will be left.
%// Load an image
Orig = double(imread('rice.png'));
%// Transform
Orig_T = dct2(Orig);
%// Split between high- and low-frequency in the spectrum (*)
cutoff = round(0.5 * 256);
High_T = fliplr(tril(fliplr(Orig_T), cutoff));
Low_T = Orig_T - High_T;
%// Transform back
High = idct2(High_T);
Low = idct2(Low_T);
%// Plot results
figure, colormap gray
subplot(3,2,1), imagesc(Orig), title('Original'), axis square, colorbar
subplot(3,2,2), imagesc(log(abs(Orig_T))), title('log(DCT(Original))'), axis square, colorbar
subplot(3,2,3), imagesc(log(abs(Low_T))), title('log(DCT(LF))'), axis square, colorbar
subplot(3,2,4), imagesc(log(abs(High_T))), title('log(DCT(HF))'), axis square, colorbar
subplot(3,2,5), imagesc(Low), title('LF'), axis square, colorbar
subplot(3,2,6), imagesc(High), title('HF'), axis square, colorbar
(*) Note on tril: The lower triangle-function operates with respect to the mathematical diagonal from top-left to bottom-right, since I want the other diagonal I'm flipping left-right before and afterwards.
Also note that this kind of operations are not usually applied to entire images, but rather to blocks of e.g. 8x8. Have a look at blockproc and this article.
An easy example:
I2 = dct_img;
I2(8:end,8:end) = 0;
I3 = idct2(I2);
imagesc(I3)
I3 can be seen as the image after low pass filter (the low frequency components), then idct2(dct_img - I2) can be viewed as high frequency.

Garment Cropping from mannequin

I have two images – mannequin with and without garment.
Please refer sample images below. Ignore the jewels, footwear on the mannequin, imagine the second mannequin has only dress.
I want to extract only the garment from the two images for further processing.
The complexity is that there is slight displacement in the position of camera when taking the two pictures. Due to this simple subtraction to generate the garment mask will not work.
Can anyone tell me how to handle it?
I think I need to do registration between the two images so that I can extract only the garment from the image?
Any references to blogs, articles and codes is highly appreciated.
--
Thanks
Idea
This is an idea of how you could do it, I haven't tested it but my gut tells me it might work. I'm assuming that there will be slight differences in the pose of the manequin as well as the camera attitude.
Let the original image be A, and the clothed image be B.
Take the difference D = |A - B|, apply a median filter that is proportional to the largest deviation you expect from pose and camera attitude error: Dmedian = Median(D, kernelsize).
Quantize Dmedian into a binary mask Dmask = Q(Dmedian, threshold) using appropriate threshold values to obtain an approximate mask for the garment (this will be smaller than the garment itself due to the median filter). Reject any shapes in Dmedian that have too small area by setting their pixels to 0.
Expand the shape(s) in Dmask proportionally to the size of the median kernel into Emask=expand(Dmask, k*kernelsize). Then construct the difference in the masks Fmask=|Dmask - Emask| which now contains areas of pixels where the garment edge is expected to be. For every pixel in Fmask which is in this area, find the correlation Cxy between A and B using a small neighbourhood, store the correlations into an image C=1.0 - Corr(A,B, Fmask, n).
Your final garment mask will be M=C+Dmask.
Explanation
Since your image has nice and continuous swatches of colour, the difference between the two similar images will be thin lines and small gradients where the pose and camera attitude is different. When taking a median filter of the difference image over a sufficiently large kernel, these lines will be removed because they are in a minority of the pixels.
The garment on the other hand will (hopefully) have a significant difference from the colors in the unclothed version. And will generate a bigger difference. Thresholding the difference after the median filter should give you a rough mask of the garment that is undersized dues to some of the pixels on the edge being rejected due to their median values being too low. You could stop here if the approximation is good enough for you.
By expanding the mask we obtained above we get a probable region for the "true" edge. The above process has served to narrow our search region for the true edge considerably and we can apply a more costly correlation search between the images along this edge to find where the garment is. High correlation means no carment and low correlation means garment.
We use the inverted correlation as an alpha value together with the initially smaller mask to obtain a alpha valued mask of the garment that can be used for extracting it.
Clarification
Expand: What I mean by "expanding the mask" is to find the contour of the mask region and outsetting/growing/enlarging it to make it larger.
Corr(A,B,Fmask,n): Is just an arbitrarily chosen correlation function that gives correlation between pixels in A and B that are selected by the mask Fmask using a region of size n. The function returns 1.0 for perfect match and 0.0 for anti-match for each pixel tested. A good function is this pseudocode:
foreach px_pos in Fmask where Fmask[px_pos] == 1
Ap = subregion(A, px_pos, size) - mean(mean(A));
Bp = subregion(B, px_pos, size) - mean(mean(B))
Cxy = sum(sum(Ap .* Bp))*sum(sum(Ap .* Bp)) / (sum(sum(Ap.*Ap))*sum(sum(Bp.*Bp)))
C[px_pos] = 1.0 - Cxy;
end
where subregion selects a region of size size around the pixel with position px_pos.
You can see that if Ap == Bp then Cxy=1