Image/Color Comparison in Objective-C - iphone

I'm trying to find a way to compare two images.
Let me give you an example so you can better understand: my App will randomize a color (she will randomize a value from 0 to 255 for the R, then for the G and then for the B and the result is a completely random RGB color).
Now the user will take a photo from the camera of the iPhone and the App will comprare the color with the image.
Example: The App select the RGB = 205,133,63 wich is brown: the user will take a picture of a brown detail of a desk. Now I need to compare the brown selected by the iPhone and the brown of the picture and display a result (for example: "the pictures is faithful to 88% compared to the given color").
I found this example in internet, but I can figure out how I can implement this in my App: http://www.youtube.com/watch?v=hWRPn7IsChI
Thanks!!
Marco

There are plenty of ways you can do this. If you want to keep it simple, you can average the colours for your entire image. For the sake of simplicity, let's say your image only has two pixels:
RGB0 = 255, 0, 0 (red)
RGB1 = 0, 0, 0 (black)
Average between the two will be
RGB_AVG = 128, 0, 0 (dark red)
Now you can calculate the difference between this average and the selected colour 205, 133, 63. This too you can do in many different ways. Here is one:
R = 205 - 128 = 80
G = 133 - 0 = 133
B = 63 - 0 = 63
Total = 80 + 133 + 63 = 276
Total score = (756 - 276) / 756 = 63.5%
This is just one way, you could collect all colours in a dictionary and count them if you need it to be super accurate. It all depends on what you want to achieve.
Btw: Reassure your numbers don't end up being higher if they are higher than your sample color. Use ABS or whatever method you want. The above is just an example.

Related

Matlab: Can't find a circle with imfindcircles [duplicate]

This question already has answers here:
Matlab: separate connected components
(2 answers)
Closed 5 years ago.
I want to understand how imfindcircles works, so I created a simple image with black background and a single white circle. The image is 640x480 and the circle has a diameter of 122 pixels:
I tried to use imfindcircles to detect the circle, I have tried various modes of the image, as uint8 RGB, uint8 grayscale, double grayscale and the reversed image, in all those forms, and with various values for minR and maxR. I got no result in all cases:
minR = 40;
maxR = 80;
Irgb = imread('example_circle.png');
Irgbr = 255 - Irgb;
I = rgb2gray(Irgb);
Ir = 255 - I;
Id = double(I)/255;
Ird = 1 - Id;
[c1,r1] = imfindcircles(I,[minR maxR]);
[c2,r2] = imfindcircles(Ir,[minR maxR]);
[c3,r3] = imfindcircles(Id,[minR maxR]);
[c4,r4] = imfindcircles(Ird,[minR maxR]);
[c5,r5] = imfindcircles(Irgb,[minR maxR]);
[c6,r6] = imfindcircles(Irgbr,[minR maxR]);
disp([length(r1) length(r2) length(r3) length(r4) length(r5) length(r6)]);
The output is:
0 0 0 0 0 0
How am I supposed to use the function to find the circle?
The imfindcircles function has a 'Sensitivity' parameter:
As you increase the sensitivity factor, imfindcircles detects more circular objects, including weak and partially obscured circles. Higher sensitivity values also increase the risk of false detection.
By setting the Sensitivity to a higher value, you get more potential circles. You could tune this parameter to always give you one circle, e.g. 0.95 seems to work fine in this specific case. This is probably not very robust though.
[c1, r1] = imfindcircles(Irgb,[40,80], 'Sensitivity', 0.95)
If you know that there will always be exactly one circle, you can set the Sensitivity to 1, which returns all potential circles. Then, use the metric output, which gives you the calculated strength of a detected circle. As you know there will be exactly one circle, you can just take the strongest one, which is always the first row.
[c, r] = imfindcircles(Irgb,[40,80], 'Sensitivity', 1);
c1 = c(1,:);
r1 = r(1,:);

Calculate hue angle range for red colours

I'm trying to correctly calculate colour hue angle range. Given an input default hue say 120 and a threshold value of 20 the range is between 100 - 140 (yes, I know - complex math).
Now in the application, when filtering an image, I can check if a given pixel falls into that range:
let inputHue = 120
let threshold = 20
let minHue = inputHue - threshold // 100
let maxHue = inputHue + threshold // 140
if (pixelHue > minHue && pixelHue < maxHue) {
// do something
}
Now the problem is with red colours range where the most saturated red colour is at 0/360 on the colour wheel. Given an input hue of 10 the minHue is now -10 (with a threshold of 20) and maxHue is 30. Because of that negative value for minHue the condition fails:
let pixelHue = 355 // this falls into a valid red range I want to get
let minHue = -10
let maxHue = 30
if (pixelHue > minHue && pixelHue < maxHue) {
// do something
}
Does anyone know how to tackle this problem of a colour wheel? I'm trying to develop a general solution that would work for any given input hue (not only red colours).
Thanks in advance.
Hues should be considered modulo 360. Hence the range for red is 0-30 AND 350-360.
Now your value of 355 passes because (355>350 AND 355<30) OR (350>30 AND (355>350 OR 355<30)).
The critical bit here starts after the first OR. In normal arithmetic, you check against lower and upper bound, and you have to pass both tests. But in modular arithmetic, if the lower bound is higher than the upper bound, the range wraps around 0 and you only need to pass one of the two both tests.
To recap: (hue>min AND hue<max) OR (min>max AND (hue>min OR hue<max))
A possible approach: Imagine both hue values as points on a circle, and compare the "shorter" angular distance between these points with the threshold:
let diff = abs(pixelHue - inputHue)
if min(diff, 360 - diff) <= threshold {
// do something
}

extract colored region

I want to extract each colored region in MATLAB after applying SRM segmentation method on a particular image.
I tried the following, but it seems that it extracts regions with different color (not the same color degree only), and with the largest area.
I = imread('./img/bfly.jpg');
imshow(I)
bw = im2bw(I);
imshow(bw)
L = bwlabel(bw);
imshow(L == 0)
props = regionprops(L);
[~,ind] = max([props.Area]);
imshow(L == ind);
Is there a way to extract each color separately?
This is an example image. I want to extract the brown color alone, the green color alone, and so on ...
Since your image appears to have no smooth variations of color, it should be straightforward to separate the colors into different images with unique to convert the image to label matrix (you could do this with rgb2ind also) followed by accumarray:
[Iu,ia,iu] = unique(reshape(I,[],3),'rows');
counts = accumarray(iu,1);
[counts,sortinds] = sort(counts,'descend');
Now say you want the N largest components:
N = 10;
largestLabels = sortinds(1:N);
Then the image for color ii:
mapi = reshape(iu == largestLabels(ii),size(I,1),size(I,2));
numeli = counts(ii)
The corresponding RGB values and the number of pixels of each color:
>> colorRegionSummary = [uint32(Iu(largestLabels,:)) counts(1:N)]
colorRegionSummary =
89 120 23 8206 % green
73 59 42 4370 % dark brown (wing)
64 128 184 2723 % blue (right shade)
105 136 25 2143 % green (bottom right shade)
64 127 178 1667 % blue (top left shade)
170 151 191 1380 % purple
58 132 201 1372 % blue (left shade)
177 130 45 1242 % orange (bottom wing shade)
184 123 50 1193 % orange (top wing shade)
118 114 56 586 % tan (top right)
Note that these are not connected components, just components with the same color. For a given mapi, you can then apply bwlabel to get the connected components for that color.
You could start with encoding the three color arrays (RGB) in a way so that you can merge them into one, two-dimensional array, e.g.
2Dimage = I(:,:,1) + 1e3*I(:,:,2) + 1e6*I(:,:,3)
that way, you get a unique number for each color: R + 1e3*G + 1e6*B. Note that each channel is encoded with a number in the interval [0, 255].
Now you can go and extract the different color regions from the image using
C = unique(2Dimage)
to obtain the unique colors you need to look for and then
for idx = 1:length(C)
find(C(idx)==2Dimage)
end
to locate the different parts of the image. The color can be readily obtained from the original image I at the corresponding locations/indices.

segment image using pixel coordinates matlab

This question maybe pretty basic, so please bear with me. I have 4 pixel coordinats and an image. I want to segment the image part within this 4 points alone and make a new image. Can you please tell me the easiest way to do this?
Look at roipoly using r and c inputs in addition to input image I.
Assuming you have a coordinate list xcoord matching with ycoord and want to have the smallest square that contains your pixels:
myImage = rand(100)
xcoord = [12 16 22 82];
ycoord = [24 70 12 34];
mySegment = myImage(xcoord(min):xcoord(max),ycoord(min):ycoord(max))

Using rectangle in Matlab. Using Sum()

I have performed rgb2gray on an image and did a sobel edge detection on the image.
then did
faceEdges = faceNoNoise(:,:) > 50; %binary threshold
so it sets the outline of the image (a picture of a face), to black and white. Values 1 is white pixel, and 0 is black pixel. Someone said I could use this,
mouthsquare = rectangle('position',[recX-mouthBoxBuffer, recY-mouthBoxBuffer, recXDiff*2+mouthBoxBuffer/2, recYDiff*2+mouthBoxBuffer/2],... % see the change in coordinates
'edgecolor','r');
numWhite = sum(sum(mouthsquare));
He said to use two sum()'s because it gets the columns and rows of the contained pixels within the rectangle. numWhite always returns 178 and some decimal numbers.
If you have a 2D matrix M (this being -- for exmple -- an image), the way to count how many elements have the value 1 is:
count_1 = sum(M(:)==1)
or
count_1 = sum(reshape(M,1,[])==1)
If the target values are not exactly 1, but have a Δ-threshold of, let's say, +/- 0.02, then one should ask for:
count_1_pm02 = sum((M(:)>=0.98) & (M(:)<=1.02))
or the equivalent using reshape.