I have a 12 bit gray-scale camera and I want to use EMGU to process the image.
My problem is that I want to process the image at "UInt16" TDepth and not the usual "Byte"
So initially I create an empty 2D image:
Image<Gray, UInt16> OnImage = new Image<Gray, UInt16>(960, 1280);
then I create a for loop to transfer my Image from 1D vector form to a 2D image:
for (int i=1; i< 960; i++)
{
for (int j = 1; j < 1280; j++)
{
OnImage[i, j] = MyImageVector[Counter];
Counter++;
}
}
where:
int[] MyImageVector = new int[1228800];
The problem is at the line :
OnImage[i, j] = MyImageVector[Counter];
where i get the following error message:
Cannot Implicitly convert type "int" to "EMGU.CV.Structure.Gray"
Why this is happening?
Do you know any way that i can store Int values to an Emgu Image object???
Any alternative workaround would be also helpful.
Thank you
I found an alternative solution to pass a 1D vector into a 2D EMGU.Image:
Image<Gray, Single> _myImage= new Image<Gray, Single>(Width, Height);
Buffer.BlockCopy(MyVector, 0, _myImage.Data, 0, MyVector.Length * sizeof(Single));
This works much faster that 2 for loops...
Related
I have a tiff Image and I am reading the RGB values of each pixel with following code. the Image Height :16198 width :12900.
But the code is taking much longer time (more than 20 minutes). tried various way like converting it to bitmap, but non of them leads to better performance. any suggestions
using (Tiff tiffreader = Tiff.Open(imgpath, "r"))
{
img.Width = tiffreader.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
img.Height = tiffreader.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
img.DipX = tiffreader.GetField(TiffTag.XRESOLUTION)[0].ToInt();
img.DipY = tiffreader.GetField(TiffTag.YRESOLUTION)[0].ToInt();
// Reading RGB values
int height = (int)img.Height;
int width = (int)img.Width;
int[] raster = new int[height*width];
var b = tiffreader.ReadRGBAImage(width, height, raster);
img.Pixels = new PColor[height, width];
img.Pixels = Utility.ConvertToRGB(height, width, raster);
}
internal static PColor[,] ConvertToRGB(int height, int width, int[] raster)
{
PColor[,] pcolor = new PColor[height, width];
try
{
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
{
int offset = (height - j - 1) * width + i;
PColor color = new PColor();
color.R = Tiff.GetR(raster[offset]);
color.G = Tiff.GetG(raster[offset]);
color.B = Tiff.GetB(raster[offset]);
pcolor[i, j] = color;
}
}
catch(Exception exp)
{
throw exp;
}
return pcolor;
}
It looks like you are doing unnecessary processing of the file. The whole loop that calls ReadScanline seems to be pointless since you just read the whole file later with a call to ReadRGBAImage. I'm not sure what class backs the img variable, but it looks like it has duplicated data in it (The Pixels property and the bytearray variable). I would see if you can refactor your code to remove one of these items.
It would also be good to change your loops to convert to RGB to have i (the height) be the inside loop so that you are accessing the raster array in order (which saves a lot of memory fetches).
Also note that 2-dimensional array access is significantly slower than 1d because of double bounds checking. In my own experience it's actually faster to calculate the offset of a 1d array manually than to use a C# 2d array. It might be worth refactoring Pixels to be 1d.
EDIT: If you can't refactor the code to remove Pixels or bytearray, then I would suggest creating the bytearray variable contents from the contents of raster instead of re-reading the file again.
I need to perform some mathematical operations in photographs, and for that I need the floating point grayscale version of an image (which might come from JPG, PNG or BMP files with various colordepths).
I used to do that in Python using PIL and scipy.ndimage, and it was very straightforward to convert to grayscale with PIL and then to an array of floating-point numbers with numpy, but now I need to do something similar in C#, and I'm confused how to do so.
I have read this very nice tutorial, that seems to be a recurring reference, but that only covers the "convert to grayscale" part, I am not sure how to get an array of doubles from a Bitmap, and then (at some moment) to convert it back to System.Drawing.Bitmap for viewing.
I'm sure there are loads of optimal ways to do this.
As #Groo points out perfectly in the comments section, one could use for instance the LockBits method to write and read pixel colors to and from a Bitmap instance.
Going even further, one could use the graphics card of the computer to do the actual computations.
Furthermore, the method Color ToGrayscaleColor(Color color) which turns a color into its
grayscale version is not optically correct. There is a set of ratios which actually need to be applied to the color component strengths. I just used 1, 1, 1 ratios. That's accceptable for me and probably horrible for an artist or a scientist.
In the comments section, #plinth was very nice to point out to this question you should look at, if you want to make an anatomically correct conversion: Converting RGB to grayscale/intensity
Just wanted to share this really easy to understand and implement solution:
First a little helper to turn a Color into it's grayscale version:
public static Color ToGrayscaleColor(Color color) {
var level = (byte)((color.R + color.G + color.B) / 3);
var result = Color.FromArgb(level, level, level);
return result;
}
Then for the color bitmap to grayscale bitmap conversion:
public static Bitmap ToGrayscale(Bitmap bitmap) {
var result = new Bitmap(bitmap.Width, bitmap.Height);
for (int x = 0; x < bitmap.Width; x++)
for (int y = 0; y < bitmap.Height; y++) {
var grayColor = ToGrayscaleColor(bitmap.GetPixel(x, y));
result.SetPixel(x, y, grayColor);
}
return result;
}
The doubles part is quite easy. The Bitmap object is a memory representation of the actual image which you can use in various operations. The colordepth and image format details are only the concern of loading and saving instances of Bitmap onto streams or files. We needn't care about those at this point:
public static double[,] FromGrayscaleToDoubles(Bitmap bitmap) {
var result = new double[bitmap.Width, bitmap.Height];
for (int x = 0; x < bitmap.Width; x++)
for (int y = 0; y < bitmap.Height; y++)
result[x, y] = (double)bitmap.GetPixel(x, y).R / 255;
return result;
}
And turning a double array back into a grayscale image:
public static Bitmap FromDoublesToGrayscal(double[,] doubles) {
var result = new Bitmap(doubles.GetLength(0), doubles.GetLength(1));
for (int x = 0; x < result.Width; x++)
for (int y = 0; y < result.Height; y++) {
int level = (int)Math.Round(doubles[x, y] * 255);
if (level > 255) level = 255; // just to be sure
if (level < 0) level = 0; // just to be sure
result.SetPixel(x, y, Color.FromArgb(level, level, level));
}
return result;
}
The following lines:
if (level > 255) level = 255; // just to be sure
level < 0) level = 0; // just to be sure
are really there in case you operate on the doubles and you want to allow room for little mistakes.
The final code, based mostly in tips taken from the comments, specifically the LockBits part (blog post here) and the perceptual balancing between R, G and B values (not paramount here, but something to know about):
private double[,] TransformaImagemEmArray(System.Drawing.Bitmap imagem) {
// Transforma a imagem de entrada em um array de doubles
// com os valores grayscale da imagem
BitmapData bitmap_data = imagem.LockBits(new System.Drawing.Rectangle(0,0,_foto_franjas_original.Width,_foto_franjas_original.Height),
ImageLockMode.ReadOnly, _foto_franjas_original.PixelFormat);
int pixelsize = System.Drawing.Image.GetPixelFormatSize(bitmap_data.PixelFormat)/8;
IntPtr pointer = bitmap_data.Scan0;
int nbytes = bitmap_data.Height * bitmap_data.Stride;
byte[] imagebytes = new byte[nbytes];
System.Runtime.InteropServices.Marshal.Copy(pointer, imagebytes, 0, nbytes);
double red;
double green;
double blue;
double gray;
var _grayscale_array = new Double[bitmap_data.Height, bitmap_data.Width];
if (pixelsize >= 3 ) {
for (int I = 0; I < bitmap_data.Height; I++) {
for (int J = 0; J < bitmap_data.Width; J++ ) {
int position = (I * bitmap_data.Stride) + (J * pixelsize);
blue = imagebytes[position];
green = imagebytes[position + 1];
red = imagebytes[position + 2];
gray = 0.299 * red + 0.587 * green + 0.114 * blue;
_grayscale_array[I,J] = gray;
}
}
}
_foto_franjas_original.UnlockBits(bitmap_data);
return _grayscale_array;
}
I'm trying to use AForge in Unity and I have trouble converting the input data.
I have a 2-dimensional array storing pixel values that I need to convert to UnmanagedImage. I came up with the following code, but I am not sure if its the most efficient way:
img = UnmanagedImage.Create(sizx,sizy, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
for (int i =0;i<sizx;i++)
for (int j =0;j<sizy;j++){
int index = i+j*sizx;
img.SetPixel(i,j, new AForge.Imaging.RGB(t[index].r, t[index].g, t[index].b).Color);
}
Any help appreciated!
I've ended up using unsafe code and accessing the UnmanagedImage.ImageData directly:
unsafe
{
byte* dst = (byte*)data.Scan0.ToPointer();
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++, src++, dst += pixelSize)
{
dst[RGB.A] = input[src].A;
dst[RGB.R] = input[src].R;
dst[RGB.G] = input[src].G;
dst[RGB.B] = input[src].B;
}
dst += offset;
}
}
As it cannot be done in Unity, I had to modify the AForge library.
If you have your image represented as a byte[] (where each value represents a pixel color value from 0 to 255), then you can use UnmanagedImage.FromByteArray to create an UnmanagedImage from those values.
This method should work on Unity.
I'm working on veins detection from image using emgu CV and I have few questions. Is there any simple way to detect color or range of colors? Is there a simple way to replace this color with another (e.g. average color of the image)? How can I achive that without degrading the performance?
Thanks in advance!
I can't imagine this problem has published about 3 years...
public static Image<Bgr, byte> BackgroundToGreen(Image<Bgr, byte> rgbimage)
{
Image<Bgr, byte> ret = rgbimage;
var image = rgbimage.InRange(new Bgr(190, 190, 190), new Bgr(255, 255, 255));
var mat = rgbimage.Mat;
mat.SetTo(new MCvScalar(200, 237, 204), image);
mat.CopyTo(ret);
return ret;
}
Why Matrix?
http://www.emgu.com/wiki/index.php/Working_with_Images#Accessing_the_pixels_from_Mat
Unlike the Image<,> class, where memory are pre-allocated and fixed, the memory of Mat can be automatically re-allocated by Open CV function calls. We cannot pre-allocate managed memory and assume the same memory are used through the life time of the Mat object. As a result, Mat class do not contains a Data property like the Image<,> class, where the pixels can be access through a managed array.
What is InRange?
http://www.emgu.com/wiki/files/2.0.0.0/html/07eff70b-f81f-6313-98a9-02d508f7c7e0.htm
Checks that image elements lie between two scalars
Return Value
res[i,j] = 255 if inrange, 0 otherwise
What is SetTo?
http://www.emgu.com/wiki/files/2.4.0/document/html/0309f41d-aa02-2c0d-767f-3d7d8ccc9212.htm
Copies scalar value to every selected element of the destination GpuMat: GpuMat(I)=value if mask(I)!=0
So it is.
Quoted from: http://blog.zsxsoft.com/post/24 (Chinese only) (CC BY-NC-ND)
Image<Bgr, Byte> img;
Image<Gray, Byte> grayImg = img.Convert<Gray, Byte>();
grayImg = img.InRange(new Bgr(minB, minG, minR), new Bgr(new Bgr(maxB, maxG, maxR);
it will only show your color(range) in binary and is the fastest
way
But if you want to detect a certain range of colors AND replace them:
Image<Bgr, Byte> img;
for (int i = 0; i < img.ManagedArray.GetLength(0); i++)
{
for (int j = 0; j < img.ManagedArray.GetLength(1); j++)
{
Bgr currentColor = img[i, j];
if (currentColor.Blue >= minB && currentColor.Blue <= maxB && currentColor.Green >= minG && maxG <= trackBar13.Value && currentColor.Red >= minR && currentColor.Red <= maxR)
{
img[i, j] = new Bgr(B,G,R);
}
}
}
I'm doing a skin detection method in c# using EmguCV. For skin detection I'm referring this article. I'm new in EmguCV. I just want to know how to get or set every pixel value of image that is capturing via webcam. If skin pixel matched it become white else black. I just want RGB value of pixel without degrading the performance of application.
to get or set every pixel value of image you do it easily as following
Image<Bgr, Byte> img = ....
for (i = 0; i < img.Height; i++)
{
for (k = 0; k < img.Width; k++)
{
// Get
// Color ( R, G, B, alpha)
Color c = img[i, k];
// Set
img[i,k] = new Bgr();
}
}
it will be write inplace