artifacts in processed images - matlab

This question is related to my previous post Image Processing Algorithm in Matlab in stackoverflow, which I already got the results that I wanted to.
But now I am facing another problem, and getting some artefacts in the process images. In my original images (stack of 600 images) I can't see any artefacts, please see the original image from finger nail:
But in my 10 processed results I can see these lines:
I really don't know where they come from?
Also if they belong to the camera's sensor why can't I see them in my original images? Any idea?
Edit:
I have added the following code suggested by #Jonas. It reduces the artefact, but does not completely remove them.
%averaging of images
im = D{1}(:,:);
for i = 2:100
im = imadd(im,D{i}(:,:));
end
im = im/100;
imshow(im,[]);
for i=1:100
SD{i}(:,:)=imsubtract(D{i}(:,:),im(:,:))
end
#belisarius has asked for more images, so I am going to upload 4 images from my finger with speckle pattern and 4 images from black background size( 1280x1024 ):
And here is the black background:

Your artifacts are in fact present in your original image, although not visible.
Code in Mathematica:
i = Import#"http://i.stack.imgur.com/5hM3u.png"
EntropyFilter[i, 1]
The lines are faint, but you can see them by binarization with a very low level threshold:
Binarize[i, .001]
As for what is causing them, I can only speculate. I would start tracing from the camera output itself. Also, you may post two or three images "as they come straight from the camera" to allow us some experimenting.

The camera you're using is most likely has a CMOS chip. Since they have independent column (and possibly row) amplifiers, which may have slightly different electronic properties, you can get the signal from one column more amplified than from another.
Depending on the camera, these variability in column intensity can be stable. In that case, you're in luck: Take ~100 dark images (tape something over the lens), average them, and then subtract them from each image before running the analysis. This should make the lines disappear. If the lines do not disappear (or if there are additional lines), use the post-processing scheme proposed by Amro to remove the lines after binarization.
EDIT
Here's how you'd do the background subtraction, assuming that you have taken 100 dark images and stored them in a cell array D with 100 elements:
% take the mean; convert to double for safety reasons
meanImg = mean( double( cat(3,D{:}) ), 3);
% then you cans subtract the mean from the original (non-dark-frame) image
correctedImage = rawImage - meanImg; %(maybe you need to re-cast the meanImg first)

Here is an answer that in opinion will remove the lines more gently than the above mentioned methods:
im = imread('image.png'); % Original image
imFiltered = im; % The filtered image will end up here
imChanged = false(size(im));% To document the filter performance
% 1)
% Compute the histgrams for each column in the lower part of the image
% (where the columns are most clear) and compute the mean and std each
% bin in the histogram.
histograms = hist(double(im(501:520,:)),0:255);
colMean = mean(histograms,2);
colStd = std(histograms,0,2);
% 2)
% Now loop though each gray level above zero and...
for grayLevel = 1:255
% Find the columns where the number of 'graylevel' pixels is larger than
% mean_n_graylevel + 3*std_n_graylevel). - That is columns that contains
% statistically 'many' pixel with the current 'graylevel'.
lineColumns = find(histograms(grayLevel+1,:)>colMean(grayLevel+1)+3*colStd(grayLevel+1));
% Now remove all graylevel pixels in lineColumns in the original image
if(~isempty(lineColumns))
for col = lineColumns
imFiltered(:,col) = im(:,col).*uint8(~(im(:,col)==grayLevel));
imChanged(:,col) = im(:,col)==grayLevel;
end
end
end
imshow(imChanged)
figure,imshow(imFiltered)
Here is the image after filtering
And this shows the pixels affected by the filter

You could use some sort of morphological opening to remove the thin vertical lines:
img = imread('image.png');
SE = strel('line',2,0);
img2 = imdilate(imerode(img,SE),SE);
subplot(121), imshow(img)
subplot(122), imshow(img2)
The structuring element used was:
>> SE.getnhood
ans =
1 1 1

Without really digging into your image processing, I can think of two reasons for this to happen:
The processing introduced these artifacts. This is unlikely, but it's an option. Check your algorithm and your code.
This is a side-effect because your processing reduced the dynamic range of the picture, just like quantization. So in fact, these artifacts may have already been in the picture itself prior to the processing, but they couldn't be noticed because their level was very close to the background level.
As for the source of these artifacts, it might even be the camera itself.

This is a VERY interesting question. I used to deal with this type of problem with live IR imagers (video systems). We actually had algorithms built into the cameras to deal with this problem prior to the user ever seeing or getting their hands on the image. Couple questions:
1) are you dealing with RAW images or are you dealing with already pre-processed grayscale (or RGB) images?
2) what is your ultimate goal with these images. Is the goal to simply get rid of the lines regardless of the quality in the rest of the image that results, or is the point to preserve the absolute best image quality. Are you to perform other processing afterwards?
I agree that those lines are most likely in ALL of your images. There are 2 reasons for those lines ever showing up in an image, one would be in a bright scene where OP AMPs for columns get saturated, thus causing whole columns of your image to get the brightest value camera can output. Another reason could be bad OP AMPs or ADCs (Analog to Digital Converters) themselves (Most likely not an ADC as normally there is essentially 1 ADC for th whole sensor, which would make the whole image bad, not your case). The saturation case is actually much more difficult to deal with (and I don't think this is your problem). Note: Too much saturation on a sensor can cause bad pixels and columns to arise in your sensor (which is why they say never to point your camera at the sun). The bad column problem can be dealt with. Above in another answer, someone had you averaging images. While this may be good to find out where the bad columns (or bad single pixels, or the noise matrix of your sensor) are (and you would have to average pointing the camera at black, white, essentially solid colors), it isn't the correct answer to get rid of them. By the way, what I am explaining with the black and white and averaging, and finding bad pixels, etc... is called calibrating your sensor.
OK, so saying you are able to get this calibration data, then you WILL be able to find out which columns are bad, even single pixels.
If you have this data, one way that you could erase the columns out is to:
for each bad column
for each pixel (x, y) on the bad column
pixel(x, y) = Average(pixel(x+1,y),pixel(x+1,y-1),pixel(x+1,y+1),
pixel(x-1,y),pixel(x-1,y-1),pixel(x-1,y+1))
What this essentially does is replace the bad pixel with a new pixel which is the average of the 6 remaining good pixels around it. The above is an over-simplified version of an algorithm. There are certainly cases where a singly bad pixel could be right next the bad column and shouldn't be used for averaging, or two or three bad columns right next to each other. One could imagine that you would calculate the values for a bad column, then consider that column good in order to move on to the next bad column, etc....
Now, the reason I asked about the RAW versus B/W or RGB. If you were processing a RAW, depending on the build of the sensor itself, it could be that only one sub-pixel (if you will) of the bayer filtered image sensor has the bad OP AMP. If you could detect this, then you wouldn't necessarily have to throw out the other good sub-pixel's data. Secondarily, if you are using an RGB sensor, to take a grayscale photo, and you shot it in RAW, then you may be able to calculate your own grayscale pixels. Many sensors when giving back a grayscale image when using an RGB sensor, will simply pass back the Green pixel as the overall pixel. This is due to the fact that it really serves as the luminescence of an image. This is why most image sensors implement 2 green sub-pixels for every r or g sub-pixel. If this is what they are doing (not ALL sensors do this) then you may have better luck getting rid of just the bad channel column, and performing your own grayscale conversion using.
gray = (0.299*r + 0.587*g + 0.114*b)
Apologies for the long winded answer, but I hope this is still informational to someone :-)

Since you can not see the lines in the original image, they are either there with low intensity difference in comparison with original range of image, or added by your processing algorithm.
The shape of the disturbance hints to the first option... (Unless you have an algorithm that processes each row separately.)
It seems like your sensor's columns are not uniform, try taking a picture without the finger (background only) using the same exposure (and other) settings, then subtracting it from the photo of the finger (prior to other processing). (Make sure the background is uniform before taking both images.)

Related

How to correlate properly a moving sample in 2 images of different size?

I am currently recording on a single camera the images, one aside of the other one, of the same sample out of a microscope.
I have 2 issues with that, and I figured out that in post procesing with Matlab I could arrange these questions.
-First, the 2 images on the camera are supposed to have the same pixel size, or one is just a litle bigger than the other one, probably because of optical pathways. What is the adapted Matlab function or way to correlate the two images so they will have exactly the same pixel size in X and Y ?
Two images on same camera , one bigger or smaller compared to the other one
-Secondly, my sample is moving a litle during the recording ( while still staying in my field of view of course ). To make my analysis easier, it would be suitable that I could correct the images so the sample remain at the same place as in the first image, to perform calculations on it easier. What would be the adapted Matlab function or way to correct this movement in the image ?
Sample moving in the image on the camera
Sorry for the poor quality of my drawings !
Thank you very much for your advices and help.
First zero-pad the images to a sufficient degree, to get them both to double the size of the bigger one.
size_padding = max(size(fig1),size(fig2));
fig1_pad = padarray(fig1,size_padding-size(fig1),'post');
fig2_pad = padarray(fig2,size_padding-size(fig2),'post');
Assuming the sample is the only feature present in the images, the best way to proceed would be to use the xcorr2() function and find the lag corresponding to the maximum correlation, to get the space shift between the two images:
xc = xcorr2(fig1_pad,fig2_pad);
[max_cc, imax] = max(abs(xc(:)));
[ypeak, xpeak] = ind2sub(size(xc),imax(1));
corr_offset = [ (ypeak-size(fig2_pad,1)) (xpeak-size(fig2_pad,2)) ];
You then use circshift() to shift one of the images using the lag you obtained in the last step.
fig2_shift = circshift(fig2_pad,corr_offset);
You now have two images of the same size, where hopefully the sample is in the same position. If you want to remove the padding zeroes, crop the images to your liking with respect to the center using imcrop().

Form a single image from multiple blocks without getting the chessboard pattern

I'm using the Hopfield neural network to process a 400x400 satellite image.
However due to hardware issues I'm unable to process the entire image as a single image. Hence I've divided it into blocks of 50x50 each.
However after processing these blocks and combining them to form a single image, the borders of the blocks show up. How can I avoid this?
Maybe you can run the same algorithm on your image twice. do it once normally, then slightly offset your blocks and do it again. then average the two together you can still see the "checkerboard" but it's not as noticeable. You may have to play with the offset to get more desirable results. Also you an probably make the code smarter so that it doens't change the image size, but this was just a quick proof of concept.
I used histogram equalization as my algorithm. You can see the "avg of blocks" looks less "chessboard-like". I even did a difference between the whole image processing and the blocks. you can see the difference is much smaller between the avg and the whole image than for either of the two blocks
offset = 25;
fun = #(block_struct) histeq(block_struct.data)
%processes entire image, this is the baseline
a = histeq(im);
%does original block processing
b = blockproc(im,[125,125],fun);
%offsets the blocks and does processing again, please notice this
%changes the size of the image
c = blockproc(im(offset:end,offset:end),[125,125],fun);
%averages the two together (using the smaller image)
d= b(offset:end,offset:end)*.5+.5*c;
%the original image shows what processing the entire image loo
figure(1)
subplot(3,2,1:2);imshow(im);title('original')
subplot(3,2,3);imshow(a);title('operation on entire image')
subplot(3,2,4);imshow(d);title('avg of blocks')
subplot(3,2,5);imshow(b);title('blocks')
subplot(3,2,6);imshow(c);title('offset block')
figure(2);suptitle('difference between operation on entire image and block images')
subplot(2,2,1);imshow(a);title('operation on entire image')
subplot(2,2,2);imshow(abs(a(offset:end,offset:end)-d));title('avg of blocks')
subplot(2,2,3);imshow(abs(a-b));title('blocks')
subplot(2,2,4);imshow(abs(a(offset:end,offset:end)-c));title('offset block')

Extract Rectangular Image from Scanned Image

I have scanned copies of currency notes from which I need to extract only the rectangular notes.
Although the scanned copies have a very blank background, the note itself can be rotated or aligned correctly. I'm using matlab.
Example input:
Example output:
I have tried using thresholding and canny/sobel edge detection to no avail.
I also tried the solution given here but it detects the entire image for cropping and it would not work for rotated images.
PS: My primary objective is to determine the denomination of the currency. There are a couple of methods I thought I could use:
Color based, since all currency notes have varying primary colors.
The advantage of this method is that it's independent of the
rotation or scale of the input image.
Detect the small black triangle on the lower left corner of the note. This shape is unique
for each denomination.
Calculating the difference between 2 images. Since this is a small project, all input images will be of the same dpi and resolution and hence, once aligned, the difference between the input and the true images can give a rough estimate.
Which method do you think is the most viable?
It seems you are further advanced than you looked (seeing you comments) which is good! Im going to show you more or less the way you can go to solve you problem, however im not posting the whole code, just the important parts.
You have an image quite cropped and segmented. First you need to ensure that your image is without holes. So fill them!
Iinv=I==0; % you want 1 in money, 0 in not-money;
Ifill=imfill(Iinv,8,'holes'); % Fill holes
After that, you want to get only the boundary of the image:
Iedge=edge(Ifill);
And in the end you want to get the corners of that square:
C=corner(Iedge);
Now that you have 4 corners, you should be able to know the angle of this rotated "square". Once you get it do:
Irotate=imrotate(Icroped,angle);
Once here you may want to crop it again to end up just with the money! (aaah money always as an objective!)
Hope this helps!

Line thickening image filter for preprocessing of scanned digits

For a school project I've built a scanner and connected it to matlab. The scanner scans images (16-by-16 pixels) of handwritten digits from 0 to 9. I'm using a principal component analysis in order to classify the scans. Due to the low accuracy of the scanner, I need to preprocess the scans first, before I can actually send them through the recognition machine.
One of these preprocessing-steps is to thicken the lines. So far, I've used a pretty simple averageing filter for this: H = ones(3, 3) ./ 9. This bears the problem, that the circular gap of the digits 8 and 9 is likely to be "closed". I enclose a picture of all my preprocessing-steps, where the problem is visible: the image with the caption "threshholded" still shows the gap, but it disappeared after the thickening step.
My question is: Do you know a better filter for this "thickening"-step, which would not erase the gap? Or do you have an idea for a filter which could be applied after the thickening to produced the desired result? Any other suggestions or hints are also greatly appreciated.
I=imread('numberreco.png');
subplot(1,2,1),imshow(I)
I=rgb2gray(I);
BW=~im2bw(I,graythresh(I));
BW2 = bwmorph(BW,'thin');
I1=double(I).*BW2;
subplot(1,2,2),imshow(uint8(I1))
The gap is kept, and you can start from here...
Not a very general answer, but if you have the Image Processing Toolbox, and your system doesn't depend on having multiple grey levels, then converting to binary images and using the 'thicken' operation from bwmorph() should do exactly what you want.
Thinking a bit harder, you could also use a suitably thickened binary image as a mask to restore holes - either just elementwise multiply it with the blurred greyscale image or, for more flexibility:
invert it to form a background/holes mask
remove the background with imclearborder() to leave just the holes
optionally dilate the mask
use as a logical index to clear the 'hole' areas of the blurred/brightened greyscale image.
Even without the morphological steps you can use a mask to artificially reintroduce the original holes later, e.g.:
bgmask = (thresholdedimage == 0); % assuming 0 == background
holes = imclearborder(bgmask);
... % other processing steps
brightenedimage(holes) = 0; % punch holes in updated image

MATLAB "CCTV" image processing, contrast filtering/feature detection

I'm a bit of a noob in MATLAB (and image processing in general) and I'm wondering if you can help me with a bit of an issue I'm having. Essentially, I'm given an image of an alley, and then multiple images of the same alley, but with different contrasts and some of the images have a picture of a robber in them. I need to be able to detect the robbers in the images, and run the same code on all of the images (i.e. I'm not allowed to custom-tailor the code for specific images). Here's what I have so far:
background = imread('backalley.jpg');
criminal = imread('backalleyX.jpg'); % Where X is the number of the image, there
%are 16 in total from 0 to 15
J = imhist(background);
K = histeq(criminal,J);
diffImage = abs(double(background)-double(K));
thresholdValue = 103;
filteredImage = diffImage > thresholdValue;
(Keep in mind I'm still playing around with the thresholdValue)
This leaves me with either a gray image if there isn't a robber, or a black and white image showing some of the features of the robber. The issue I'm having is that three of the 16 images with a very high contrast initially leave me with most of the features of the alley still visible, even after having histogram equalization done. Is there anything I can do to filter these images or adjust the contrast better, that won't cause an issue with the rest of the successfully processed images? Unfortunately since I'm new here I can't post images showing what's going on, sorry.
EDIT: Here is a link to the photobucket album: http://s997.photobucket.com/user/52TulaSKS/library/Image%20Processing
All of the images needing processing are there, as well as the original, and examples of processed images. I gave titles to the important ones (original, ones giving me trouble, and the examples of correctly and incorrectly processed images).
Change your threshold to a higher value.