How to compare two image with c - c

I'd like to implement an algorithm capable of comparing two images using the C api of OpenCV 3.0.0 .
The image are captured by webcam so they have the same resolution (don't worry is small) and the same file format (jpeg) (but we can change it if we want)
My idea is to get two image, transform in b&w and with a simple for construct compare bit by bit.
In b&w we can consider the image as a full matrix with 0s and 1s.
Example :
Image1 (black and white)
0 0 0 1
0 1 0 1
0 0 0 0
0 0 1 1
So i know there's a lot of way to do it with opencv but i read a lot of example that are useless for me.
So my idea is to manually operate with every pixel. Considering the image as a matrix we can compare pixel by pixel with a simple double construct for (pixel_image[r:rows][c:columns] == pixel_image2[r:rows][c:columns] only if the "pixel" is considered as integer. So the problem is how can i access to the value of pixel from IplImage type?
Certainly in this way i think i have a bad optimization of code, or maybe i can't adapt it to a large scale of image data.
(Please don't answer me with: "use c++ - use python - c is deprecated ecc..", i know there're so many way to do it in easy way with an high level code)
Thanks to all.

Ok i solved.
This way u can access the value of single pixel (if the image is loaded as RGB)( rememeber that opencv see BGR)
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
double tmpb,tmpg,bmpr;
for(int i=0;i<img->height;i++){
for(int j=0;j<img->width;j++){
tmpb=cvGet2D(img,i,j).val[0];
tmpg=cvGet2D(img,i,j).val[1];
tmpr=cvGet2D(img,i,j).val[2];
}
}
If the image is a single channel (for example if we convert it to black and white) is
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
int tmp
for(int i=0;i<img->height;i++){
for(int j=0;j<img->width;j++){
tmp=cvGet2D(img,i,j).val[0];
printf("Value: %d",tmp);
}
}

Related

Uniform random sampling of CIELUV for RGB colors

Selecting a random color on a computer is a touch harder than I thought it would be.
The naive way of uniform random sampling of 0..255 for R,G,B will tend to draw lots of similar greens. It would make sense to sample from a perceptually uniform space like CIELUV.
A simple way to do this is to sample L,u,v on a regular mesh and ensure the color solid is contained in the bounds (I've seen different bounds for this). If the sample falls outside embedded RGB solid (tested by mapping it XYZ then RGB), reject it and sample again. You can settle for a kludgy-but-guaranteed-to-terminate "bailout" selection (like the naive procedure) if you reject more then some arbitrary threshold number of times.
Testing if the sample lies within RGB needs to be sure to test for the special case of black (some implementations end up being silent on the divide by zero), I believe. If L=0 and either u!=0 or v!=0, then the sample needs to be rejected or else you would end up oversampling the L=0 plane in Luv space.
Does this procedure have an obvious flaw? It seems to work but I did notice that I was rolling black more often than I thought made sense until I thought about what was happening in that case. Can anyone point me to the right bounds on the CIELUV grid to ensure that I am enclosing the RGB solid?
A useful reference for those who don't know it:
https://www.easyrgb.com/en/math.php
The key problem with this is that you need bounds to reject samples that fall outside of RGB. I was able to find it worked out here (nice demo on page, API provides convenient functions):
https://www.hsluv.org/
A few things I noticed with uniform sampling of CIELUV in RGB:
most colors are green and purple (this is true independent of RGB bounds)
you have a hard time sampling what we think of as yellow (very small volume of high lightness, high chroma space)
I implemented various strategies that focus on sampling hues (which is really what we want when we think of "sampling colors") by weighting according to the maximum chromas at that lightness. This makes colors like chromatic light yellows easier to catch and avoids oversampling greens and purples. You can see these methods in actions here (select "randomize colors"):
https://www.mysticsymbolic.art/
Source for color randomizers here:
https://github.com/mittimithai/mystic-symbolic/blob/chromacorners/lib/random-colors.ts
Okay, while you don't show the code you are using to generate the random numbers and then apply them to the CIELUV color space, I'm going to guess that you are creating a random number 0.0-100.0 from a random number generator, and then just assigning it to L*.
That will most likely give you a lot of black or very dark results.
Let Me Explain
L* of L * u * v* is not linear as to light. Y of CIEXYZ is linear as to light. L* is perceptual lightness, so an exponential curve is applied to Y to make it linear to perception but then non-linear as to light.
TRY THIS
To get L* with a random value 0—100:
Generate a random number between 0.0 and 1.0
Then apply an exponent of 0.42
Then multiply by 100 to get L*
Lstar = Math.pow(Math.random(), 0.42) * 100;
This takes your random number that represents light, and applies a powercurve that emulates human lightness perception.
UV Color
As for the u and v values, you can probably just leave them as linear random numbers. Constrain u to about -84 and +176, and v to about -132.5 and +107.5
Urnd = (Math.random() - 0.5521) * 240;
Vrnd = (Math.random() - 0.3231) * 260;
Polar Color
It might be interesting converting uv to LChLUV or LshLUV
For hue, it's probably as simple as H = Math.random() * 360
For chroma contrained 0—178: C = Math.random() * 178
The next question is, should you find chroma? Or saturation? CIELUV can provide either Hue or Sat — but for directly generating random colors, it seems that chroma is a bit better.
And of course these simple examples are not preventing over-runs, so they color values to be tested to see if they are legal sRGB or not. There's a few things that can be done to constrain the generated values to legal colors, but the object here was to get you to a better distribution without excess black/dark results.
Please let me know of any questions.

SDL pixel has wrong values

I am trying to create a image processing software.
I get some weird results trying to create an Unsharp Mask effect.
I will attach my code here and I will explain what it does and where the problems are (or at least , where I think they are):
void unsharpMask(SDL_Surface* inputSurface,SDL_Surface* outputSurface)
{
Uint32* pixels = (Uint32*)inputSurface->pixels;
Uint32* outputPixels=(Uint32*)outputSurface->pixels;
Uint32* blurredPixels=(Uint32*)blurredSurface->pixels;
meanBlur(infoSurface,blurredSurface);
for (int i=0;i<inputSurface->h;i++)
{
for(int j=0;j<inputSurface->w;j++)
{
Uint8 rOriginal,gOriginal,bOriginal;
Uint8 rBlurred,gBlurred,bBlurred;
Uint32 rMask,gMask,bMask;
Uint32 rFinal,gFinal,bFinal;
SDL_GetRGB(blurredPixels[i*blurredSurface->w+j],blurredSurface->format,&rBlurred,&gBlurred,&bBlurred);
SDL_GetRGB(pixels[i*inputSurface->w+j],inputSurface->format,&rOriginal,&gOriginal,&bOriginal);
rMask=rOriginal - rBlurred;
rFinal=rOriginal + rMask;
if(rFinal>255) rFinal=255;
if(rFinal<=0) rFinal=0;
gMask=gOriginal - gBlurred;
gFinal=gOriginal + gMask;
if(gFinal>255) gFinal=255;
if(gFinal<0) gFinal=0;
bMask=bOriginal - bBlurred;
bFinal=bOriginal + bMask;
if(bFinal>255) bFinal=255;
if(bFinal<0) bFinal=0;
Uint32 pixel =SDL_MapRGB(outputSurface->format,rFinal,gFinal,bFinal);
outputPixels[i *outputSurface->w+j]=pixel;
}
}
}
So, as you can see, my function gets 2 arguments: the image source(from which pixel data will be extracted, and a target, where the image will be projected). I blur the original image, then i subtract the RGB value of the blurred image from the source image to get "the mask" and then , i add the mask to the original image and that's it. I added some clamping to make sure everything stays in the correct range and then I draw every pixel resulted on the output surface. All these surfaces have been converted in an SDL_PIXELFORMAT_ARGB8888 . The output surface is loaded into a texture (also SDL_PIXELFORMAT_ARGB8888) and rendered on the screen.
The results are pretty good in 90% of the image, I get the effect I want, however , there are some pixels that look weird in some places.
Original:
Result:
I tried to fix this in any possible way I knew. I thought is a format problem and played with the pixel bit depth , but I couldn't get to a good result. What i found is that all the values > 255 are negative values and I tried to make them completely white. And it works for the skies ,for example, but if you can see on my examples, the dark values, on the grass are also affected, which makes this not a good solution.
I also get this kind of wrong pixels when I want to add a contrast or do sharpen using kernel convolution, and the values are really bright/dark.
In my opinion there may be a problem with the pixel format, but I'm not sure if that's true.
Is there anyone that had this kind of problem before or knows a potential solution?

Strange behavior with Matlab array

I am having some trouble manually creating a histogram of intensity values from a grayscale image. Below is the code that I am using the create the bins for the plot that I want to create. The code works fine for every bin except for the last two. For some reason if the intensity is 254 or 255 it puts both values into the 254 bin and no values are accumulated in the 255 bin.
bins= zeros(1,256);
[x,y]=size(grayImg);
for i = 1:x
for j = 1:y
current = grayImg(i,j);
bins(current+1) = bins(current+1) + 1;
end
end
plot(bins);
I do not understand why this behavior is happening. I have printed out the count of 254 intensities and 255 intensities and they are both correct. However, when using the above code to accumulate the intensity values it does not work correctly.
Edit: Added the image I am using, the incorrect graph(the one I get with above code), and the correct one
A. The first problem with your code is the initial definition of bins. It seems that you come from C or somthing like that, but the definition should be- bins=zeros(1,256);
B. The second point is that you don't need the nested loop, you have a matlab function especially for that:
bins=hist(grayImg(:),1:256); % now, you don't need the pre-definition for 'bins'.
plot(bins);
C. Try to use functions like bar or imhist or hist(grayImg(:)), it may save you all this, and give a nice plot.

Stuck in a lab Task (image processing)

Hi everyone I am new to programming and I am first year in university cs.
my question Is that I am writing a program that screens simple images looking
for anomalies (indicated by excessive patterns of red). The program should load a
file and then print out whether or not the image contains more than a certain percentage
of intensive red pixels.
so far I have the following code:
#include <stdio.h>
#include "scc110img.h"
int main()
{
unsigned char* imageArray = LoadImage("red.bmp");
int imageSize =GetSizeOfImage();
int image;
for (image = 0; image<imageSize; image++);
printf("%d\n, imageArray[image]");
}
my question is how can I modify the program o that it prints out the amount of blue, green and red.
something like;
blue value is 0, green value is 0, red value is 0.
You have a byte array (unsigned char) that represents the bytes of your image. Currently you are printing them out one byte at a time.
So to know how to get the individual rgb values you need to know how they were stored.
Its as easy as that, but don't expect someone here to do it for you.
This code is really incomplete. We don't know what your LoadImage() or GetSizeOfImage() function does but one thing is sure is that the way you are representing image in you C program is definitely not the way it is represented. A 'bmp' image has several parts and you should find out the correct way to represent it as a struct. Then you can traverse through it pixel by pixel.
I would suggest using a library pre-written such as 'libbmp' to make your task easy.

[EDITED]Implementing Difference of Gaussian

I'm not sure if I'm doing the right way.
IplImage *dog_1 = cvCreateImage(cvGetSize(oriImg), oriImg->depth, oriImg->nChannels);
IplImage *dog_2 = cvCreateImage(cvGetSize(oriImg), oriImg->depth, oriImg->nChannels);
int kernel2 = 1;
int kernel1 = 5;
cvSmooth(oriImg, dog_2, CV_GAUSSIAN, kernel2, kernel2);
cvSmooth(oriImg, dog_1, CV_GAUSSIAN, kernel1, kernel1);
cvSub(dog_2, dog_1, dst, 0);
Am I doing the right way? Is the above the correct way of doing DOG? I just tried it from the explanation from wiki. But I could not get the desired image like in the wiki page http://en.wikipedia.org/wiki/Difference_of_Gaussians
[Edited]
I quote this from wiki page
"Difference of Gaussians is a grayscale image enhancement algorithm that involves the subtraction of one blurred version of an original grayscale image from another, less blurred version of the original. The blurred images are obtained by convolving the original grayscale image with Gaussian kernels having different standard deviations."
While reading a paper, the DoG image is done by
Original image, I(x,y) -> Blurs -> I1(x,y)
I1(x,y) -> Blurs -> I2(x,y)
output = I2(x,y) - I1(x,y)
As you see it's a slightly different from what I'm doing where I get the I1 and I2 using different kernel from the original image
Which one is the correct one or I misinterpret the meaning in the wiki?
If the image you've attached is your sample output, it doesn't necessarily look wrong. The DoG operation is quite simple: blur with two Gaussians of different sizes and compute the difference image. That appears to be what your code is doing, so I'd say you have it right.
If your worries stem from looking at the Wikipedia article (where the image is predominantly white, rather than black), it is just the inversion of the image that you have. I would not worry about that.

Resources