Kinect skeleton resizing / image reszing ? - c#

I previously posted concerning c# kinect image comparison , I've overcome a number of the problems by taking screenshots of the skeleton stream on a black background in order to get over the problems inherent with comparing photos , Now my problem is that I need the images of the user to be compared to the presaved movements , however I'm having trouble when the users are not the same height as me , is there a way of overcoming this ? my only ideas involve either resizing the image or comparing the positions of certain colored pixels

It depends on how you want to compare the images. If you want to compare them pixel by pixel, You don't really need to resize, you just need a ratio to be used in the for-loop. For example if the size of image1 is WIDTH1*HEIGHT1 and the size of image2 is WIDTH2*HEIGHT2, you can use a for loop like this:
for(int i = 0; i < WIDTH1; i++)
{
for(int j = 0; j < HEIGHT1; j++)
{
pixel1 = image1[i][j];
pixel2 = image2[i * WIDTH2/WIDTH1][j * HEIGHT2/HEIGHT1];
// compare
}
}
A more elegant method would be to compare pixel1 with a combination of multiple pixels from image2. For example if image1 is 300*300 and image2 is 600*600, then you can compare each pixel of image1 with the average RGB of 4 pixels in image2 (since for every pixel in image1, there exists four pixels in image2). In case the sizes are not divisible to each other, you may use weighted average. For example if image1 is 300*300 and image2 is 400*400, then you can compare pixel1 of image1 with a weighted average of 4 pixels in image2:
pixel1 = image1[i][j];
pixel2 = 0.75 * image2[i * WIDTH2/WIDTH1][j * HEIGHT2/HEIGHT1] +
0.25 * AVERAGE(image2[i * WIDTH2/WIDTH1 + 1][j * HEIGHT2/HEIGHT1] +
image2[i * WIDTH2/WIDTH1][j * HEIGHT2/HEIGHT1 + 1] +
image2[i * WIDTH2/WIDTH1 + 1][j * HEIGHT2/HEIGHT1 + 1]);
Basically it means: pixel2 is 75% one pixel and 25% its neighbour pixels. With doing this you are actually doing a simple resizing algorithm (combining 4 different pixels into 1).

Related

Get most similar image [duplicate]

This question already has answers here:
How can I measure the similarity between two images? [closed]
(17 answers)
Closed 5 years ago.
I have one Bitmap A and one array of Bitmap, in the array there is a Bitmap that looks the same as Bitmap A. I'm using the code below but it sometimes doesnt work, it iterates the entire array without finding it, it seems there are some minor differences, is there a way to change the function to return true if its 90% similar or pick the most similar image in the array? The array has only 6 images.
for(int i = 0; i < list.Count;i++)
{
if(ImageCompareString(image,list[i])
{
answerIndex = i;
break;
}
}
private static bool ImageCompareString(Bitmap firstImage, Bitmap secondImage)
{
MemoryStream ms = new MemoryStream();
firstImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
String firstBitmap = Convert.ToBase64String(ms.ToArray());
ms.Position = 0;
secondImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
String secondBitmap = Convert.ToBase64String(ms.ToArray());
if (firstBitmap.Equals(secondBitmap))
{
return true;
}
else
{
return false;
}
}
Of course there is such way... But you have to code it yourself.
First you shoud not compare the base64 data... You'll loose direct pixel value access and increase the size of the data to compare by more then 150% (Originaly 200% but corrected thanks to PeterDuniho's comment) in C# due to UTF16.
Second I assume that all pictures have the same fixed size. Before comparing, reduce the image size to something really small, but keep the width/height aspect. This will speed up the comparsion and also eliminates noise.
Third Iterate both pictures and compare their grayscaled pixel values. I Assume that you have resized the picture to 16x16. Since we're comparing their grayscale-values the value of one pixel is between 0 and 255. So the maximum distance between both pictures will be 16 * 16 * 256 = 65536. If both pictures are black, the distance between the pictures will be zero (100% similarity). If one picture is black and the other is white the distance will be 65535 (0% similarity).
To compare the images iterate the picture-pixels and subtract the grayscale-pixel-value-from-picture-a from the grayscale-pixel-value-of-picture-b at the point x,y and add the absolute difference value to the counter. This counter will be the total distance between both pictures.
Lets assume this counter has a value of 1000 after the comparison loop, you get the percentage-similarity by 1000 / 65535 ~ 1.5% difference (or 98.5% similarity) between both pictures.
pseudo-compare-code
long counter = 0;
long total = image.Width * image.Height * (Color.White - Color.Black);
for(int x = 0; x < image.Width; x++)
{
for(int y = 0; y < image.Height; y++)
{
var p1 = image.GetPixel(x, y);
var p2 = otherImage.GetPixel(x, y);
var g1 = ((p1.R + p1.G + p1.B) / 3);
var g2 = ((p2.R + p2.G + p2.B) / 3);
var distance = Math.Abs(g1 - g2);
counter += distance;
}
}
var similarity = 100 - ((counter / total) * 100);
This is an more or less easy approach, but you have to test this with you scenario/images. Instead of comparing grayscale-values you could also compare rgb-values. Look for distance definitions like the euclidean distance... Start and keep reading :)
EDIT
This is just a really basic approach that should explain how you can start comparing images. It does not take into account that there might be different image formats (jpeg, png, gif), color formats (indexed, 16bit, 24bit, 32bit) or images with different resolutions.

Space represented by a single Kinect pixel at a given depth

Basically I want to take a fixed straight line across the devices point of view and determine if anything intercepts it but in my example I want to make the "laser line" configurable with regards to the distance from the top of the field of view.
Now it's easy enough to get the depth data at a given pixel point simply by doing this.
var depthInMM = DepthImagePixel.Depth;
and its also easy to simply say I want to focus on the 100th line of pixels from the top by doing something like this.
for (int i = 0; i < this._DepthPixels.Length; ++i) //_DepthPixels.Length is obviously 307200 for 640x480
{
if (i >= 64000 && i <= 64640) //Hundredth vertical pixel line
{
//Draw line or whatever
}
}
Which ends up with something like this.
BUT for example I might want to have the line intercept at 50 cm from the top of the field of view at 3 meters depth. Now obviously I understand that as the depth increases so does the area represented but I cannot find any reference or myself work out how to calculate this relationship.
So, how can one calculate the coordinate space represented at a given depth utilizing the Kinect sensor. Any help sincerely appreciated.
EDIT:
So if I understand correctly this can be implemented as such in C#
double d = 2; //2 meters depth
double y = 100; //100 pixels from top
double vres = 480; //480 pixels vertical resolution
double vfov = 43; //43 degrees vertical field of view of Kinect
double x = (2 * Math.Sin(Math.PI * vfov / 360) * d * y) / vres;
//x = 0.30541768893691434
//x = 100 pixels down is 30.5 cm from top field of view at 2 meters depth
2 sin(PI VFOV / 360) D Y
X = --------------------------
VRES
X: distance of your line from the top of the image in meters
D: distance - orthogonal to the image plane - of your line from the camera in meters
Y: distance of your line from the top of the image in pixels
VRES: vertical resolution of the image in pixels
VFOV: vertical field of view of the camera in degrees

Comparing images and labeling the differences c#

I am currently working on a project in which I am required to write software that compares two images made up of the same area and draws a box around the differences. I wrote the program in c# .net in a few hours but soon realized it was INCREDIBLY expensive to run. Here are the steps I implemented it in.
Created a Pixel class that stores the x,y coordinates of each pixel and a PixelRectangle class that stores a list of pixels along with width,height,x and y properties.
Looped through every pixel of each image, comparing the colour of each corresponding pixels. If the colour was different I then created a new pixel object with the x,y coordinates of that pixel and added it to a pixelDifference List.
Next I wrote a method that recursively checks each pixel in the pixelDifference list to create PixelRectangle objects that only contain pixels that are directly next to each other. (Pretty sure this bad boy is causing the majority of the destruction as it gave me a stack overflow error.)
I then worked out the x,y coordinates and dimensions of the rectangle based on the pixels that were stored in the list of the PixelRectangle Object and drew a rectangle over the original image to show where the differences were.
My questions are: Am I going about this the correct way? Would a quad tree hold any value for this project? If you could give me the basic steps on how something like this is normally achieved I would be grateful. Thanks in advance.
Dave.
looks like you want to implement blob detection. my suggestion is not to reinvent the wheel and just use openCVSharp or emgu to do this. google 'blob detection' & opencv
if you want to do it yourself here my 2 cents worth:
first of all, let's clarify what you want to do. really two separate things:
compute the difference between two images (i am assuming they are
the same dimensions)
draw a box around 'areas' that are 'different' as measured by 1. questions here are what is an 'area' and what is considered 'different'.
my suggestion for each step:
(my assumption is both images a grey scale. if not, compute the sum of colours for each pixel to get grey value)
1) cycle through all pixels in both images and subtract them. set a threshold on the absolute difference to determine if their difference is sufficient to represent and actual change in the scene (as opposed to sensor noise etc if the images are from a camera). then store the result in a third image. 0 for no difference. 255 for a difference. if done right this should be REALLY fast. however, in C# you must use pointers to get a decent performance. here an example of how to do this (note: code not tested!!) :
/// <summary>
/// computes difference between two images and stores result in a third image
/// input images must be of same dimension and colour depth
/// </summary>
/// <param name="imageA">first image</param>
/// <param name="imageB">second image</param>
/// <param name="imageDiff">output 0 if same, 255 if different</param>
/// <param name="width">width of images</param>
/// <param name="height">height of images</param>
/// <param name="channels">number of colour channels for the input images</param>
unsafe void ComputeDiffernece(byte[] imageA, byte[] imageB, byte[] imageDiff, int width, int height, int channels, int threshold)
{
int ch = channels;
fixed (byte* piA = imageB, piB = imageB, piD = imageDiff)
{
if (ch > 1) // this a colour image (assuming for RGB ch == 3 and RGBA == 4)
{
for (int r = 0; r < height; r++)
{
byte* pA = piA + r * width * ch;
byte* pB = piB + r * width * ch;
byte* pD = piD + r * width; //this has only one channels!
for (int c = 0; c < width; c++)
{
//assuming three colour channels. if channels is larger ignore extra (as it's likely alpha)
int LA = pA[c * ch] + pA[c * ch + 1] + pA[c * ch + 2];
int LB = pB[c * ch] + pB[c * ch + 1] + pB[c * ch + 2];
if (Math.Abs(LA - LB) > threshold)
{
pD[c] = 255;
}
else
{
pD[c] = 0;
}
}
}
}
else //single grey scale channels
{
for (int r = 0; r < height; r++)
{
byte* pA = piA + r * width;
byte* pB = piB + r * width;
byte* pD = piD + r * width; //this has only one channels!
for (int c = 0; c < width; c++)
{
if (Math.Abs(pA[c] - pB[c]) > threshold)
{
pD[c] = 255;
}
else
{
pD[c] = 0;
}
}
}
}
}
}
2)
not sure what you mean by area here. several solutions depending on what you mean. from simplest to hardest.
a) colour each difference pixel red in your output
b) assuming you only have one area of difference (unlikely) compute the bounding box of all 255 pixels in your output image. this can be done using a simple max / min for both x and y positions on all 255 pixels. single pass through the image and should be very fast.
c) if you have lots of different areas that change - compute the "connected components". that is a collection of pixels that are connected to each other. of course this only works in a binary image (i.e. on or off, or 0 and 255 as in our case). you can implement this in c# and i have done this before. but i won't do this for you here. it's a bit involved. algorithms are out there. again opencv or google connected components.
once you have a list of CC's draw a box around each. done.
You're pretty much going about it the right way. Step 3 shouldn't be causing a StackOverflow exception if it's implemented correctly so I'd take a closer look at that method.
What's most likely happening is that your recursive check of each member of PixelDifference is running infinitely. Make sure you keep track of which Pixels have been checked. Once you check a Pixel it no longer needs to be considered when checking neighbouring Pixels. Before checking any neighbouring pixel make sure it hasn't already been checked itself.
As an alternative to keeping track of which Pixels have been checked you can remove an item from PixelDifference once it has been checked. Of course, this may require a change in the way you implement your algorithm since removing an element from a List while checking it can bring a whole new set of issues.
There's a much simpler way of finding the difference of two images.
So if you have two images
Image<Gray, Byte> A;
Image<Gray, Byte> B;
You can get their differences fast by
A - B
Of course, images don't store negative values so to get differences in cases where pixels in image B are greater than image A
B - A
Combining these together
(A - B) + (B - A)
This is ok, but we can do even better.
This can be evaluated using Fourier transforms.
CvInvoke.cvDFT(A.Convert<Gray, Single>().Ptr, DFTA.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_FORWARD, -1);
CvInvoke.cvDFT(B.Convert<Gray, Single>().Ptr, DFTB.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_FORWARD, -1);
CvInvoke.cvDFT((DFTB - DFTA).Convert<Gray, Single>().Ptr, AB.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_INVERSE, -1);
CvInvoke.cvDFT((DFTA - DFTB).Ptr, BA.Ptr, Emgu.CV.CvEnum.CV_DXT.CV_DXT_INVERSE, -1);
I find that the results from this method are much better.
You can make a binary image out of this, ie: threshold the image so pixels with no change have 0 while pixels that have changes store 255.
Now as far as the second part of the problem goes, I suppose there's a simple crude solution:
Partition the image into rectangular regions. Perhaps there's no need to go as far as using quad trees. Say, an 8x8 grid... (For different results, you can experiment with different grid sizes).
Then use the convex hull function within these regions. These convex hulls can be turned into rectangles by finding the min and max x an y coordinates of their vertices.
Should be fast and simple

Image analysis on scientific chromatograms

I am looking for a way to extract information out of a chromatogram out of a GC or HPLC. A chromatogram looks like this:
I am not really into image processing/analysis so I'm looking for a tool/algorithim to extract the length (and the surface under a peak if possible) of a peak from those chromatograms. The solutions can either be in Python or in C#.
Thanks in advance.
I've written some quick python code that will extract chromatogram (or any single-valued) data from an image file.
It has the following requirements:
Image is clean (no text or other data).
Curve is single valued, ie. curve pixel width of one (it will still work without this, but it will always take the upper value).
Scales are linear.
It is very simple, and just iterates through each column of the image and takes the first black value as the data point. It uses PIL. These data points are initially in the image co-ordinate system, so need to be rescaled to the data co-ordinate system, if all your images share the same axis, this is straight forward, otherwise it needs to be done manually on a per image basis (automation would be more involved).
The image below shows where I extracted your image (I removed the text) for processing (non-pink region), so for re-scaling we just take the white box region in the data co-ordinate system: x_range = 4.4 - 0.55, x_offset = 0.55, y_range = 23000 - 2500, and y_offset = 2500.
Here is the extracted data replotted with pyplot:
Here is the code:
import Image
import numpy as np
def get_data(im, x_range, x_offset, y_range, y_offset):
x_data = np.array([])
y_data = np.array([])
width, height = im.size
im = im.convert('1')
for x in xrange(width):
for y in xrange(height):
if im.getpixel((x, y)) == 0:
x_data = np.append(x_data, x)
y_data = np.append(y_data, height - y)
break
x_data = (x_data / width) * x_range + x_offset
y_data = (y_data / height) * y_range + y_offset
return x_data, y_data
im = Image.open('clean_data_2.png')
x_data, y_data = get_data(im,4.4-0.55,0.55,23000-2500,2500)
from pylab import *
plot(x_data, y_data)
grid(True)
savefig('new_data.png')
show()
Once you have your data as numpy arrays, there are many options you can use to find peaks and the corresponding areas under them (see this discussion for some approaches). Noise is a large concern, so a general approach would be to convolve the data to smooth the noise out (or you could threshold if your peaks are sharp) then differentiate to find peaks. To find areas under peaks you can do numerical integration across the peak region.
I've made a couple of assumptions and written some simple code (below), to illustrate a possible approach. I've thresholded the data so only peaks above 5000 survive, then we iterate through the data finding the peaks, and using the trapeze rule, np.trapz, to find the area under each peak. Where peaks overlap the areas are split at the overlap point (I doubt this is standard..). Also this code will only recognize peaks that are local maxima (shoulders will not be detected). I've graphed the results, writing the area values for each peak at the corresponding peak position:
def find_peak(start, grad):
for index, gr in enumerate(grad[start:]):
if gr < 0:
return index + start
def find_end(peak, grad):
for index, gr in enumerate(grad[peak:]):
if gr >= 0:
return index + peak + 1
def find_peaks(grad):
peaks=[]
i = 0
while i < len(grad[:-1]):
if grad[i] > 0:
start = i
peak_index = find_peak(start, grad)
end = find_end(peak_index, grad)
area = np.trapz(y_data[start:end], x_data[start:end])
peaks.append((x_data[peak_index], y_data[peak_index], area))
i = end - 1
else:
i+=1
return peaks
y_data = np.where(y_data > 5000, y_data, 0)
grad = np.diff(y_data)
peaks = find_peaks(grad)
from pylab import *
plot(x_data, y_data)
for peak in peaks:
text(peak[0], 1.01*peak[1], '%d'%int(peak[2]))
grid(True)
show()
Whatever approach you take at this point requires assumptions about your data (which I am not really in a position to make! Although I made a few above!), how do you deal with overlapping peaks? etc.. I am sure there are standard approaches in chromatography, so really you need to check that out first. Hope this helps!
When i use this code I get the following image
The code is the same as above (with slight modifications)
from PIL import Image
import numpy as np
def get_data(im, x_range, x_offset, y_range, y_offset):
x_data = np.array([])
y_data = np.array([])
width, height = im.size
im = im.convert('1')
for x in range(width):
for y in range(height):
if im.getpixel((x, y)) == 0:
x_data = np.append(x_data, x)
y_data = np.append(y_data, height - y)
break
x_data = (x_data / width) * x_range + x_offset
y_data = (y_data / height) * y_range + y_offset
return x_data, y_data
im = Image.open('C:\Python\HPLC.png')
x_data, y_data = get_data(im,4.4-0.55,0.55,23000-2500,2500)
from pylab import *
plot(x_data, y_data)
grid(True)
savefig('new_data.png')
show()
I am not quite sure what the problem might be.

Resizing an image in cm C#

I have an requirement that asks for an image with 10 X 6,88 cm.
I know that I can't simple convert from cm to pixels, cause one pixel size depends on the user display resolution.
I would like to know if there is a way to resize an image to have that size in cm. (I need to keep the image extension also. e.g.: can't convert it to a pdf or other extension)
It really depends on in which resolution the user will print the image (sizes in cm makes little sense other than when printed). If the user wants to make a print in, say 200 dpi, then the image would need to be (10 / 2.54 * 200) by (6.88 / 2.54 * 200) pixels (the division with 2.54 is needed to convert between cm and inches). Which resolution that is needed is highly dependent on what kind of image it is, and the quality requirements of the user.
So just saying "I want to resize to X by Y cm" does not really make sense.
For a code sample on how to make the actual resize once you have figured out the needed size of the image, this SO answer should cover your needs.
Actually, you have to differentiate between the images size on the screen, and the images size on the printout.
usually, you find the formula:
inches = pixels / dpi
so it follows:
pixel = inches * dpi
This is for print, actually.
For the display, replace dpi with ppi, and there you are.
For those (like me) that are not familiar with inches:
inches = pixels / dpi
pixel = inches * dpi
1 centimeter = 0.393700787 inch
pixel = cm * 0.393700787 * dpi
This routine will calculate the pixel-size to have the image display X-cm on the monitor.
But on the printer, you don't have it that easy, since you can't get the DPI as easy as the PPI (bmp.HorizontalResolution & bmp.VerticalResolution).
public static int Cm2Pixel(double WidthInCm)
{
double HeightInCm = WidthInCm;
return Cm2Pixel(WidthInCm, HeightInCm).Width;
} // End Function Cm2Pixel
public static System.Drawing.Size Cm2Pixel(double WidthInCm, double HeightInCm)
{
float sngWidth = (float)WidthInCm; //cm
float sngHeight = (float)HeightInCm; //cm
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1, 1))
{
sngWidth *= 0.393700787f * bmp.HorizontalResolution; // x-Axis pixel
sngHeight *= 0.393700787f * bmp.VerticalResolution; // y-Axis pixel
}
return new System.Drawing.Size((int)sngWidth, (int)sngHeight);
} // End Function Cm2Pixel
usage would go like this:
public System.Drawing.Image Generate(string Text, int CodeSize)
{
int minSize = Cm2Pixel(2.5); // 100;
if (CodeSize < minSize)
CodeSize = minSize;
if (string.IsNullOrEmpty(Text))
{
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(CodeSize, CodeSize);
using (System.Drawing.Graphics gfx = System.Drawing.Graphics.FromImage(bmp))
{
gfx.Clear(System.Drawing.Color.Black);
using(System.Drawing.Font fnt = new System.Drawing.Font("Verdana", 12, System.Drawing.FontStyle.Bold))
{
double y = CodeSize / 2.0 - fnt.Size;
gfx.DrawString("No Data", fnt, System.Drawing.Brushes.White, 5, (int)y, System.Drawing.StringFormat.GenericTypographic);
} // End Using fnt
} // End using gfx
return bmp;
} // End if (string.IsNullOrEmpty(Text))
...[Generate QR-Code]
return [Generated QR-Code]
}
Image file formats like JPG and TIFF have an EXIF header which has information like horizontal and vertical DPI.
Thus if you get an image that has this metadata, you could verify the printable size.
double DPC = Image_DPI * 0.393700787;
double widthInCm = Image_Width * DPC;
double heightInCm = Image_Height * DPC;
if (widthInCm <= 10 && heightInCm <= 6.88) // do stuff
If you need to resize images to never exceed these printable dimensions, you could do it the other way around, and calculate a DPI ratio that lets the image of dimensions W x H fit within 10cm x 6.88cm bounds.
Kind of what Fredrik is saying:
I would take a nice DPI and require the image to be that resolution or bigger (but is the same aspect ratio) and when exporting/printing the image, resize the image to the DPI used by the other program/printer...
It might be as simple as this: most images store the number of pixels per inch in them. Figure out the number of pixels in each dimension of your image, and divide that by the number of inches (convert from cm). Then use the original bits, just modify the field for the number of pixels per inch (or, more commonly, dots per inch).
So your picture needs to be 3.93" x 2.71". If your image is 393px x 271px, you would set the dpi to 100x100. If your image is 39px x 27px, you would set the dpi to 10x10.
Though probably you'll have to do some resizing, as explained by other answers. :)

Categories

Resources