Reputation: 1953
So I am trying to make an opencv program that can detect which cells of a pillbox have pills in them.
My initial idea was to:
However, in practice, I can't really seem to find good edges using canny, since the camera is a poor quality raspberry pi camera.
Does anybody have any suggestions of how I can go about finding the outlines of the 14 cells?
UPDATE:
So I've put masking tape on the edges of the walls, and through some processing, am able to obtain images like the following
Now, how do I get the 14 masks of the interiors of the 14 cells? I tried doing a hough transform on this image, but it's still creating spurious lines it shouldn't, and not creating lines it should
Upvotes: 1
Views: 966
Reputation: 60770
Considering that you control the imaging conditions, I would suggest you improve them a bit.
First of all have your camera point straight down to the surface that the pillbox is on. That will make the geometry of the pillbox a lot simpler.
Also try to avoid shadows. They're not impossible to deal with, but the problem is easier without. A good illumination makes most computer vision problems easy.
You have a red box on a white background. Segmenting out the box should be easy (just detect red pixels). Find the largest connected component, then identify the four corners. This gives you a rectangle. Since you know the geometry of the box, all you need to do now is divide the rectangle into a 7x2 grid. This removes the need to detect individual cells.
If you really want to detect individual cells, consider painting the edges of the cells in black. Again, facing a difficult vision problem, adjust your world until the problem is easy. :)
EDIT
It's a good idea to use blue masking tape. The blue comes out nicely in the photograph. The JPEG compression does make it more difficult than necessary to distinguish colors, I hope you can read and process the images without passing through JPEG. Here's what I've got:
There is a bit of perspective distortion that I didn't bother with. It should be possible to correct for that too, since finding the box outline is simple, and that tells you all you need to know about the distortion.
I've used MATLAB, because that is what I'm most familiar with to do a quick prototype. I hope you won't have trouble translating this to Python. I used the DIPimage toolbox, which has a Python counterpart, PyDIP (all functionality I'm using is available from within Python). Here is the GitHub repository.
% Read in image
img = imread('https://i.sstatic.net/AXkGH.jpg');
img = joinchannels('rgb',img);
% Convert to Lab color space
lab = colorspace(img,'lab');
% Get red area, make it into a single large blob, and measure its orientation
red = lab{2} > 30;
red = closing(red,20);
msr = measure(red,[],'feret');
[~,indx] = max(msr);
angle = msr(indx(1)).feret(5);
% Rotate the original image to make the box horizontal
img = colorspace(rotation(img,-angle-pi/2,'linear','add max'),'rgb'); % BUG! rotation loses color space
% Convert to Lab color space again
lab = colorspace(img,'lab');
% Get blue masking tape
blue = lab{3} < -10;
% Poor man's Radon transform -- horizontal lines
horiz = sum(blue,[],1);
% Expect three peaks
horiz = gaussf(horiz,3);
peaks = find(maxima(horiz));
horiz = double(horiz(peaks));
[~,indx] = sort(horiz,'descend');
horiz = sort(peaks(indx(1:3))); % 3 largest maxima
% Poor man's Radon transform -- vertical lines
vert = sum(blue,[],2);
% Expect eight peaks
vert = gaussf(vert,3);
peaks = find(maxima(vert));
vert = double(vert(peaks));
[~,indx] = sort(vert,'descend');
vert = sort(peaks(indx(1:8))); % 8 largest maxima
% Draw lines over rotated input image
for ii=1:8
img(vert(ii),horiz(1):horiz(end)) = [0,255,0];
end
for ii=1:3
img(vert(1):vert(end),horiz(ii)) = [0,255,0];
end
Upvotes: 0