JavaCV findContours outlining the image instead of finding the contour - opencv

I am trying to find that whether there is any rectangle/square present inside my area of interest. Here is what I have achieved till now.
Below is the region of interest which I snipped out of the original image using JavaCV.
Mat areaOfInterest = OpenCVUtils.getRegionOfInterest("image.jpg",295,200,23,25);
public static Mat getRegionOfInterest(String filePath , int x, int y, int width, int height){
Mat roi = null;
try{
Mat image = Imgcodecs.imread(filePath);
Rect region_of_interest= new Rect(x,y,width,height);
roi = image.submat(region_of_interest);
}catch (Exception ex){
}
return roi;
}
Now I'm trying to find whether there is any rectangle present in the area of interest. I have used following lines of code to detect that as well.
Mat gray = new Mat();
Mat binary = new Mat();
Mat hierarchy = new Mat();
ArrayList<MatOfPoint> contours = new ArrayList<>();
cvtColor(image,gray,COLOR_BGR2GRAY);
Core.bitwise_not(gray,binary);
findContours(binary,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE);
if(contours.size() > 0){
for (MatOfPoint contour:contours) {
Rect rect = boundingRect(contour);
/// x = 0, y = 1 , w = 2, h =3
Point p1 = new Point(rect.x,rect.y);
Point p2 = new Point(rect.width + rect.x, rect.height+rect.y);
rectangle(image,p1,p2,new Scalar(0,0,255));
Imgcodecs.imwrite("F:\\rect.png",image);
}
}
But instead of finding the the square inside the image it is outlining the parts of the image as following.
It would be great if someone pushes me in the right direction.

OpenCV's findContours() treats the input image as binary, where everything that is 0 is black, and any pixel >0 is white. Since you're reading a jpg image, the compression makes it so that most white pixels aren't exactly white, and most black pixels aren't exactly black. Thus, if you have an input image like:
3 4 252 250 3 1
3 3 247 250 3 2
3 2 250 250 2 2
4 4 252 250 3 1
3 3 247 250 3 2
3 2 250 250 2 2
then findContours() will just outline the whole thing, since to it it's equivalent to all being 255 (they're all > 0).
All you need to do is binarize the image with something like threshold() or inRange(), so that your image actually comes out to
0 0 255 255 0 0
0 0 255 255 0 0
0 0 255 255 0 0
0 0 255 255 0 0
0 0 255 255 0 0
0 0 255 255 0 0
Then you'd correctly get the outline of the 255 block in the center.

Related

Is there cumulative sum function in DM-scripting?

I would like to do cumulative sum along x or y direction of the image data.
Is there any function in DM-scripting like "cumsum" in Matlib?
Thanks!
for example an image of 4x4 pixels the pixel values are
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
cumulative sum along x direction will result in:
1 1+2=3 1+2+3=6 1+2+3+4=10
2 5 9 14
3 7 12 18
4 9 15 22
There are differnt ways to achieve this, but potentially the fastest and easiest is to create a "fully binned" version of the image.
image img := GetFrontImage()
number sizeX, sizeY
img.GetSize( sizeX, sizeY )
image vSum = Rebin( img, 1, sizeY )
image hSum = Rebin( img, sizeX, 1 )
vSum.SetName( "vertical sum" )
vSum.ShowImage()
hSum.SetName( "horizontal sum" )
hSum.ShowImage()
If you want a 2D image as a result, where each pixel holds the sum of all its pixels to the left, you can do this by adding up offset images:
image img := GetFrontImage()
number sizeX, sizeY
img.GetSize( sizeX, sizeY )
image vCumSum := img.ImageClone()
for( number x = 1; x<sizeX ; x++ )
{
hCumSum += offset( img, -x, 0 )
}
hCumSum.SetName( "horizontal sum (cumulative)" )
hCumSum.ShowImage()
Alternatively, you can create an expression using intrinsic variables as in
image img := GetFrontImage()
image hCumSum := 0 * img.ImageClone()
hCumSum += img[icol,irow] + hCumSum[ icol - 1, irow ]
hCumSum.SetName( "horizontal sum (cumulative)" )
hCumSum.ShowImage()
GMS 3.4 also offers a dedicated, speed optimized command:
RealImage Project( BasicImage img, Number axis )
RealImage Project( BasicImage img, Number axis, Boolean rescale )
void Project( BasicImage img, BasicImage dst, Number axis )
void Project( BasicImage img, BasicImage dst, Number axis, Boolean rescale )
Another way to do projection is by matrix multiplication. multiply a 2-D image by a 1-D matrix of 1's will project the image onto 1-D accumulation.
number d0, d1
image HProject, VProject, ones, img
img:=getfrontImage()
img.getSize(d0,d1)
ones:=exprSize(1,d0,1)
HProject=MatrixMultiply(img,ones)
HProject.rotateLeft()
HProject.showImage()
ones:=exprSize(d1,1,1)
VProject=MatrixMultiply(ones,img)
VProject.showImage()
I also have one
image cumsum(image img)
// computes the cumulative sum along x direction
{
number sx, sy
img.GetSize(sx,sy)
for(number i=1; i<sx; i++)
{
img[0,i,sy,i+1]=img[0,i-1,sy,i]+img[0,i,sy,i+1]
}
return img
}
image im=getfrontimage()
im=im.cumsum()
im.showimage()

Changing Pixel values in Mat opencv

I am trying to work with am RGB image in Opencv. From the image i only want to keep the red pixels and the rest i want to set to white. I am unsure how to do this logic in opencv. The image is read as Mat.
I wrote the following code but its not working.
Mat image;
for(i to rows)
for(j to col)
{
b=input[image.step * j + i]
g=input[image.step * j + i + 1]
r=input[image.step * j + i + 2]
if(r == 255 && g&b == 0)
{
image.at<Vec3f>(j,i)=img.at<Vec3F>(j,i)
}
else image.push_back(0);
This is the code i wrote
I am sure its incorrect but I am unable to do it. Can i get some help
You would like to keep only those pixels which are purely red, i.e. red is 255 and green, and blue is zeros. Basically, you want to change those pixels which does not satisfy that condition:
if(~(red == 255 and green == 0 and blue == 0))
red = green = blue = 255
Below is the code in python:
img = cv2.imread(filename)
rows , cols , layers = img.shape
for i in range(rows):
for j in range(cols):
if(~(img[i][j][2] == 255 and img[i][j][0] == 0 and img[i][j][1] == 0)):
img[i][j][0] = img[i][j][1] = img[i][j][2] = 255

CIAreaHistogram inputScale factor

I'm building an application that uses the CIAreaHistogram Core Image filter. I use an inputCount value (number of buckets) of 10 for testing, and an inputScale value of 1.
I get the CIImage for the histogram itself, which I then run through a custom kernel (see end of post) to set alpha values to 1 (since otherwise the alpha value from the histogram calculations is premultiplied) and then convert it to an NSBitmapImageRep.
I then scan through the image rep's buffer and print the RGB values (skipping the alpha values). However, when I do this, the sum of the R, G, and B values across the 10 do not necessarily add up to 255.
For example, with a fully black image, I apply the histogram, then the custom kernel, and get the following output:
RGB: 255 255 255
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
RGB: 0 0 0
This is as I expect, since all pixels are black, so everything is in the first bucket. However, if I run the same algorithm with a color image, I get the following:
RGB: 98 76 81
RGB: 164 97 87
RGB: 136 161 69
RGB: 100 156 135
RGB: 80 85 185
RGB: 43 34 45
RGB: 31 19 8
RGB: 19 7 3
RGB: 12 5 2
RGB: 16 11 11
Add up the values for R, G, and B - they don't add up to 255. This causes problems because I need to compare two of these histograms, and my algorithm expects the sums to be between 0 and 255. I could obviously scale these values, but I want to avoid that extra step for performance reasons.
I noticed something else interesting that might give some clue as to why this is happening. In my custom kernel, I simply set the alpha value to 1. I tried a second kernel (see end of post) that sets all pixels to red. Clearly, green and blue values are zero. However, I get this result when checking the values from the bitmap rep:
RGB: 255 43 25
But I just set G and B to zero! This seems to be part of the problem, which indicates color management. But since I explicitly set the values in the kernel, there's only one block of code where this can be happening - the conversion to an NSBitmapImageRep from the CIImage from the filter:
NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCIImage:kernelOutput];
unsigned char *buf = [bitmapRep bitmapData];
Once I set the pixels to RGB 255 0 0, then execute those lines, then read the buffer, the RGB values are all 255 43 25. I have further tried setting the color space of the original CGImageRef on which the entire workflow is based to kCGColorSpaceGenericRGB, thinking the color profile may be carrying through, but to no avail.
Can anyone tell me why a CIFilter kernel would behave this way, and how I could solve it?
As mentioned before, here are copies of the CIFilter kernel functions I use. First, the one that sets alpha to 1:
kernel vec4 adjustHistogram(sampler src)
{
vec4 pix = sample(src, destCoord());
pix.a = 1.0;
return pix;
}
And next, the one that sets all pixels to RGB 255 0 0 but that ends up 255 43 25 once it converts to NSBitmapImageRep:
kernel vec4 adjustHistogram(sampler src)
{
vec4 pix = sample(src, destCoord());
pix.r = 1.0; pix.g = 0.0; pix.b = 0.0;
pix.a = 1.0;
return pix;
}
Thanks in advance for your help.
You only need one line of code to generate and display a histogram when using a custom Core Image filter (or whenever you are creating a new CIImage object or are replacing an existing one):
return [CIFilter filterWithName:#"CIHistogramDisplayFilter" keysAndValues:kCIInputImageKey, self.inputImage, #"inputHeight", #100.0, #"inputHighLimit", #1.0, #"inputLowLimit", #0.0, nil].outputImage;

Filter for red hue - emgucv/opencv

How do I filter an image for red hue? I understand that red lies around zero between 330° and 30° (represented by 165 to 15 in OpenCV?). How can I use that range with the InRange method as there is an overflow at 360° (180 in OpenCV)?
Im detecting HUE colour using the following code:
Mat img_hsv, dst ;
cap >> image;
cvtColor(image, img_hsv, CV_RGB2HSV);
inRange(img_hsv, Scalar(110, 130, 100), Scalar(140, 255, 255), dst );
where dst is Mat of the same size as img_hsv and CV_8U type.
And your scalars determine the filtered colour. In my case its:
HUE from 110 to 140
SAT from 130 to 255
VAL from 100 to 255
more info here:
OpenCV 2.4 InRange()
I'm not sure about using a hue that overflows the 180 range but I think you can calculate them separately and then add the resulting Mats.

FFT Convolution - Really low PSNR

I'm convoluting an image (512*512) with a FFT filter (kernelsize=10), it looks good.
But when I compare it with an image which I convoluted the normal way the result was horrible.
The PSNR is about 35.
67,187/262,144 Pixel values have a difference of 1 or more(peak at ~8) (having a max pixel value of 255).
My question is, is it normal when convoluting in frequency space or might there be a problem with my convolution/transforming functions? . Because the strange thing is that I should get better results when using double as data-type. But it stays COMPLETELY the same.
When I transform an image into frequency space, DON'T convolute it, then transform it back it's fine and the PSNR is about 140 when using float.
Also, due to the pixel differences being only 1-10 I think I can rule out scaling errors
EDIT: More Details for bored interested people
I use the open source kissFFT library. With real 2dimensional input (kiss_fftndr.h)
My Image Datatype is PixelMatrix. Simply a matrix with alpha, red, green and blue values from 0.0 to 1.0 float
My kernel is also a PixelMatrix.
Here some snippets from the Convolution function
Used datatypes:
#define kiss_fft_scalar float
#define kiss_fft_cpx struct {
kiss_fft_scalar r;
kiss_fft_scalar i,
}
Configuration of the FFT:
//parameters to kiss_fftndr_alloc:
//1st param = array with the size of the 2 dimensions (in my case dim={width, height})
//2nd param = count of the dimensions (in my case 2)
//3rd param = 0 or 1 (forward or inverse FFT)
//4th and 5th params are not relevant
kiss_fftndr_cfg stf = kiss_fftndr_alloc(dim, 2, 0, 0, 0);
kiss_fftndr_cfg sti = kiss_fftndr_alloc(dim, 2, 1, 0, 0);
Padding and transforming the kernel:
I make a new array:
kiss_fft_scalar kernel[width*height];
I fill it with 0 in a loop.
Then I fill the middle of this array with the kernel I want to use.
So if I would use a 2*2 kernel with values 1/4, 1/4, 1/4 and 1/4 it would look like
0 0 0 0 0 0
0 1/4 1/4 0
0 1/4 1/4 0
0 0 0 0 0 0
The zeros are padded until they reach the size of the image.
Then I swap the quadrants of the image diagonally. It looks like:
1/4 0 0 1/4
0 0 0 0
0 0 0 0
1/4 0 0 1/4
now I transform it: kiss_fftndr(stf, floatKernel, outkernel);
outkernel is declarated as
kiss_fft_cpx outkernel= new kiss_fft_cpx[width*height]
Getting the colors into arrays:
kiss_fft_scalar *red = new kiss_fft_scalar[width*height];
kiss_fft_scalar *green = new kiss_fft_scalar[width*height];
kiss_fft-scalar *blue = new kiss_fft_scalar[width*height];
for(int i=0; i<height; i++) {
for(int j=0; i<width; j++) {
red[i*height+j] = input.get(j,i).getRed(); //input is the input image pixel matrix
green[i*height+j] = input.get(j,i).getGreen();
blue{i*height+j] = input.get(j,i).getBlue();
}
}
Then I transform the arrays:
kiss_fftndr(stf, red, outred);
kiss_fftndr(stf, green, outgreen);
kiss_fftndr(stf, blue, outblue); //the out-arrays are type kiss_fft_cpx*
The convolution:
What we have now:
3 transformed color arrays from type kiss_fft_cpx*
1 transformed kernel array from type kiss_fft_cpx*
They are both complex arrays
Now comes the convolution:
for(int m=0; m<til; m++) {
for(int n=0; n<til; n++) {
kiss_fft_scalar real = outcolor[m*til+n].r; //I do that for all 3 arrys in my code!
kiss_fft_scalar imag = outcolor[m*til+n].i; //so I have realred, realgreen, realblue
kiss_fft_scalar realMask = outkernel[m*til+n].r; // and imagred, imaggreen, etc.
kiss_fft_scalar imagMask = outkernel[m*til+n].i;
outcolor[m*til+n].r = real * realMask - imag * imagMask; //Same thing here in my code i
outcolor[m*til+n].i = real * imagMask + imag * realMask; //do it with all 3 colors
}
}
Now I transform them back:
kiss_fftndri(sti, outred, red);
kiss_fftndri(sti, outgreen, green);
kiss_fftndri(sti, outblue, blue);
and I create a new Pixel Matrix with the values from the color-arrays
PixelMatrix output;
for(int i=0; i<height; i++) {
for(int j=0; j<width; j++) {
Pixel p = new Pixel();
p.setRed( red[i*height+j] / (width*height) ); //I divide through (width*height) because of the scaling happening in the FFT;
p.setGreen( green[i*height+j] );
p.setBlue( blue[i*height+j] );
output.set(j , i , p);
}
}
Notes:
I already take care in advance that the image has a size with a power of 2 (256*256), (512*512) etc.
Examples:
kernelsize: 10
Input:
Output:
Output from normal convolution:
my console says :
142519 out of 262144 Pixels have a difference of 1 or more (maxRGB = 255)
PSNR: 32.006027221679688
MSE: 44.116752624511719
though for my eyes they look the same °.°
Maybe one person is bored and goes through the code. It's not urgent, but it's a kind of problem I just want to know what the hell I did wrong ^^
Last, but not least, my PSNR function, though I don't really think that's the problem :D
void calculateThePSNR(const PixelMatrix first, const PixelMatrix second, float* avgpsnr, float* avgmse) {
int height = first.getHeight();
int width = first.getWidth();
BMP firstOutput;
BMP secondOutput;
firstOutput.SetSize(width, height);
secondOutput.SetSize(width, height);
double rsum=0.0, gsum=0.0, bsum=0.0;
int count = 0;
int total = 0;
for(int i=0; i<height; i++) {
for(int j=0; j<width; j++) {
Pixel pixOne = first.get(j,i);
Pixel pixTwo = second.get(j,i);
double redOne = pixOne.getRed()*255;
double greenOne = pixOne.getGreen()*255;
double blueOne = pixOne.getBlue()*255;
double redTwo = pixTwo.getRed()*255;
double greenTwo = pixTwo.getGreen()*255;
double blueTwo = pixTwo.getBlue()*255;
firstOutput(j,i)->Red = redOne;
firstOutput(j,i)->Green = greenOne;
firstOutput(j,i)->Blue = blueOne;
secondOutput(j,i)->Red = redTwo;
secondOutput(j,i)->Green = greenTwo;
secondOutput(j,i)->Blue = blueTwo;
if((redOne-redTwo) > 1.0 || (redOne-redTwo) < -1.0) {
count++;
}
total++;
rsum += (redOne - redTwo) * (redOne - redTwo);
gsum += (greenOne - greenTwo) * (greenOne - greenTwo);
bsum += (blueOne - blueTwo) * (blueOne - blueTwo);
}
}
fprintf(stderr, "%d out of %d Pixels have a difference of 1 or more (maxRGB = 255)", count, total);
double rmse = rsum/(height*width);
double gmse = gsum/(height*width);
double bmse = bsum/(height*width);
double rpsnr = 20 * log10(255/sqrt(rmse));
double gpsnr = 20 * log10(255/sqrt(gmse));
double bpsnr = 20 * log10(255/sqrt(bmse));
firstOutput.WriteToFile("test.bmp");
secondOutput.WriteToFile("test2.bmp");
system("display test.bmp");
system("display test2.bmp");
*avgmse = (rmse + gmse + bmse)/3;
*avgpsnr = (rpsnr + gpsnr + bpsnr)/3;
}
Phonon had the right idea. Your images are shifted. If you shift your image by (1,1), then the MSE will be approximately zero (provided that you mask or crop the images accordingly). I confirmed this using the code (Python + OpenCV) below.
import cv
import sys
import math
def main():
fname1, fname2 = sys.argv[1:]
im1 = cv.LoadImage(fname1)
im2 = cv.LoadImage(fname2)
tmp = cv.CreateImage(cv.GetSize(im1), cv.IPL_DEPTH_8U, im1.nChannels)
cv.AbsDiff(im1, im2, tmp)
cv.Mul(tmp, tmp, tmp)
mse = cv.Avg(tmp)
print 'MSE:', mse
psnr = [ 10*math.log(255**2/m, 10) for m in mse[:-1] ]
print 'PSNR:', psnr
if __name__ == '__main__':
main()
Output:
MSE: (0.027584912741602553, 0.026742391458366047, 0.028147870144492403, 0.0)
PSNR: [63.724087463606452, 63.858801190963192, 63.636348220531396]
My advice for you to try to implement the following code :
A=double(inputS(1:10:length(inputS))); %segmentation
A(:)=-A(:);
%process the image or signal by fast fourior transformation and inverse fft
fresult=fft(inputS);
fresult(1:round(length(inputS)*2/fs))=0;
fresult(end-round(length(fresult)*2/fs):end)=0;
Y=real(ifft(fresult));
that's code help you to obtain the same size image and good for remove DC component ,the you can to convolution.

Resources