How to convert Image<Gray, Byte> to Image<Gray, float>? - c#

I'm trying to substract 1 image from another, somewhat like this:
Image<Gray, float> result, secondImage;
Image<Gray, byte> firstImage;
result = firstImage - secondImage;
But it gives an error
Operator '-' cannot be applied to operands of type 'Emgu.CV.Image<Emgu.CV.Structure.Gray,byte>' and 'Emgu.CV.Image<Emgu.CV.Structure.Gray,float>'
Maybe i need to convert firstImage into Image<Gray, float> type. But I don't know how to do it.

To quote from the documentation:
Color and Depth Conversion
Converting an Image between different colors and depths are simple. For example, if you have Image img1 and you wants to convert it to a grayscale image of Single, all you need to do is
Image<Gray, Single> img2 = img1.Convert<Gray, Single>();
So, in your case, you could use
result = firstImage.Convert<Gray, float>() - secondImage;

Related

Negative values when comparing two histograms

I am using EmguCV(c#) histogram to compare two HSV images. But sometimes I get negative values. I assumed that when I compare 2 histogram values, the value will be in the interval <0 and 1>. However, some of the values of hue or saturation are sometimes negative numbers like -0.145.
Firstly, I get byte image array, which I convert into Image<Hsv, Byte> - img1.
Image<Hsv, Byte> img1 = null;
Mat byteImageMat = new Mat();
Mat hsvMat = new Mat();
CvInvoke.Imdecode(request.ByteImage, Emgu.CV.CvEnum.ImreadModes.AnyColor, byteImageMat);
CvInvoke.CvtColor(byteImageMat, hsvMat, ColorConversion.Bgr2Hsv);
img1 = hsvMat.ToImage<Hsv, Byte>();
Then I create DenseHistogram and spliting individual channels.
DenseHistogram ComparedHistoHue = new DenseHistogram(180, new RangeF(0, 180));
DenseHistogram ComparedHistoSaturation = new DenseHistogram(256, new RangeF(0, 256));
DenseHistogram ComparedHistoBrightness = new DenseHistogram(256, new RangeF(0, 256));
Image<Gray, Byte> hueChannel = img1[0];
Image<Gray, Byte> saturationChannel = img1[1];
Image<Gray, Byte> brightnessChannel = img1[2];
After that I calculate histograms
ComparedHistoHue.Calculate(new Image<Gray, Byte>[] { hueChannel }, false, null);
ComparedHistoSaturation.Calculate(new Image<Gray, Byte>[] { saturationChannel }, false, null);
ComparedHistoBrightness.Calculate(new Image<Gray, Byte>[] { brightnessChannel }, false, null);
At this point, I loaded histogram from file which I created before and assign it into Mat (loadedMatHue, loadedMatSaturation and loadedMatBrightness).
double hue = CvInvoke.CompareHist(loadedMatHue, ComparedHistoHue, Emgu.CV.CvEnum.HistogramCompMethod.Correl);
double satuation = CvInvoke.CompareHist(loadedMatSaturation, ComparedHistoSaturation, Emgu.CV.CvEnum.HistogramCompMethod.Correl);
double brightnes = CvInvoke.CompareHist(loadedMatBrightness, ComparedHistoBrightness, Emgu.CV.CvEnum.HistogramCompMethod.Correl);
Can somebody tell me, why is in hue or saturation variable negative value? In my opinion and tests, there is always only one negative value at one momemnt across the double variables.
For HSV, the idea that the numbers would be between 0 and 1 is incorrect. If you want your image to have values between 0 and 1, then that image would have to be in grayscale.
In HSV, you split it up into three definitions, Hue, Saturation, and Value.
Hue is stored from 0 to 360 degrees, but can become negative if you rotate the hue past 0.
Saturation is considered from 0 to 1, i.e grayscale values. If you have negative values in this channel, disregard them, as the lowest that this value should be is 0. The same can be said for the highest value, which will be 1 since the highest value of a grayscale channel can only be one. Like I said before, its best to think of this channel in terms of grayscale from 0 to 1.
Value is very similar to saturation, the only difference being that value is considered the "lightness of the color, by the given S[saturation]" This value also can only be between 0 and 1, and any values outside of this space should be clipped.
If you want a more in depth explanation, you can check out this Stack post, which is very detailed and I thought it should be credited in this post.
If you do have to clip these values, you can always access the pixel values for each channel using some sample code below.
Image<Hsv,Byte> sampleImage = new Image<Hsv,Byte>("path\to\image");
//X and y are the pixel coordinates on an image
//Hue channel
byte hue = sampleImage.Data[y,x,0];
//Saturation channel
byte sat = sampleImage.Data[y,x,1];
//Value channel
byte val = sampleImage.Data[y,x,2];
You can throw these values inside of a loop and check if a pixel is outside the boundaries, and if it is replace it with the high or low value respectively.

How to match EMGU CV SIFT keypoints of two images?

I want code to match two pictures on basis of SIFT keypoints.?
I have the following code for SIFT
public static Image<Bgr, Byte> siftFunction(Bitmap sourceBitmap)
{
Image<Gray, Byte> modelImage = new Image<Gray, byte>(sourceBitmap);
SIFTDetector siftCPU = new SIFTDetector();
VectorOfKeyPoint modelKeyPoints = new VectorOfKeyPoint();
MKeyPoint[] mKeyPoints = siftCPU.DetectKeyPoints(modelImage, null);
modelKeyPoints.Push(mKeyPoints);
ImageFeature<float>[] reulst = siftCPU.ComputeDescriptors(modelImage, null, mKeyPoints);
Image<Bgr, Byte> result = Features2DToolbox.DrawKeypoints(modelImage, modelKeyPoints, new Bgr(Color.Red), Features2DToolbox.KeypointDrawType.DEFAULT);
return result;
}
one solution is to use the provided example of object detection and then compare the area of detection. In case the whole observed image corresponds to the model image - your images match.
other solution - do not use the descriptors at all but just select the key points. Then compare the key points arrays of the two pictures and in case of equality consider the images to be matching.
first solution is somehow more reliable while the second is faster and easier.

Histogram computation with Emgu OpenCV

I would like to get the histogram of an image using Emgu.
I have a Gray scale double image
Image<Gray, double> Crop;
I can get a histogram using
Image<Gray, byte> CropByte = Crop.Convert<Gray, byte>();
DenseHistogram hist = new DenseHistogram(BinCount, new RangeF(0.0f, 255.0f));
hist.Calculate<Byte>(new Image<Gray, byte>[] { CropByte }, true, null);
The problem is, doing it this way I needed to convert to a byte Image. This is problematic because it skews my results. This gives a slightly different histogram to what I would get if it were possible to use a double image.
I have tried using CvInvoke to use the internal opencv function to compute a histogram.
IntPtr[] x = { Crop };
DenseHistogram cropHist = new DenseHistogram
(
BinCount,
new RangeF
(
MinCrop,
MaxCrop
)
);
CvInvoke.cvCalcArrHist(x, cropHist, false, IntPtr.Zero);
The trouble is I'm finding it hard to find how to use this function correctly
Does emgu/opencv allow me to do this? Do I need to write the function myself?
This is not an EmguCV/OpenCV issue, the idea itself makes no sense as a double histogram would require a lot more memory than what's available. What I say is true when you have an histogram allocated with a fixed size. The only way to go around this would be to have an histogram with dynamic allocation as the image is processed. But this would be dangerous with big images as it could allocate as much memory as the image itself.
I guess that your double image contains many identical values, otherwise an histogram would not be very useful. So one way to go around this is to remap your values to a short (16-bits) instead of byte (8-bits) this way your histogram would be quite similar to what you expect from your double values.
I had a look in histogram.cpp in the opencv source code.
Inside function
void cv::calcHist( const Mat* images, int nimages, const int* channels,
InputArray _mask, OutputArray _hist, int dims, const int* histSize,
const float** ranges, bool uniform, bool accumulate )
There is a section which handles different image types
if( depth == CV_8U )
calcHist_8u(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
else if( depth == CV_16U )
calcHist_<ushort>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
else if( depth == CV_32F )
calcHist_<float>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
else
CV_Error(CV_StsUnsupportedFormat, "");
While double images are not handled here yet, float is.
While floating point looses a little bit of precision from double, its not a significant problem.
The following code snippet worked well for me
Image<Gray, float> CropByte = Crop.Convert<Gray, float>();
DenseHistogram hist = new DenseHistogram(BinCount, new RangeF(0.0f, 255.0f));
hist.Calculate<float>(new Image<Gray, float>[] { CropByte }, true, null);

HoughLines invalid arguments

Hi am using HoughLines Method to detect lines from a camera, i've filtered my image "imgProcessed" using ROI it means getting just the black objects to make the tracking simple, then when i intend to use the HoughLines method it gives me an error that my "CannyEdges" has some invalid arguments, here's my code :
Image<Gray, Byte> gray = imgProcessed.Convert<Gray, Byte>().PyrDown().PyrUp();
Gray cannyThreshold = new Gray(180);
Gray cannyThresholdLinking = new Gray(120);
Gray circleAccumulatorThreshold = new Gray(120);
Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking);
LineSegment2D[] lines = imgProcessed.cannyEdges.HoughLines(
cannyThreshold,
cannyThresholdLinking,
1, //Distance resolution in pixel-related units
Math.PI / 45.0, //Angle resolution measured in radians.
50, //threshold
100, //min Line width
1 //gap between lines
)[0]; //Get the lines from the first channel
I've edited my code & it works, i've devised it in two parts : the first part where i've detected the canny edges rather then use the HoughLines method to detect it automatically, and the 2nd where i've used the HoughLinesBinary method rather than HoughLines with less arguments, here is the code :
Image<Gray, Byte> gray1 = imgProcessed.Convert<Gray, Byte>().PyrDown().PyrUp();
Image<Gray, Byte> cannyGray = gray1.Canny(120, 180);
imgProcessed = cannyGray;
LineSegment2D[] lines = imgProcessed.HoughLinesBinary(
1, //Distance resolution in pixel-related units
Math.PI / 45.0, //Angle resolution measured in radians.
50, //threshold
100, //min Line width
1 //gap between lines
)[0]; //Get the lines from the first channel

How to convert Bgr pixel to Hsv pixel in EmguCV?

I'd like to convert a Bgr value (one pixel) to an Hsv value. How can I do that (without writing the conversion code from scratch) in EmguCV?
Please note that I am not interested in converting whole image's color space but only one pixel, therefore CvInvoke.cvCvtColor() does not work for me.
If you want to do this within EmguCV just read the image into a Image the get the value of the pixel and stick it in a Hsv structure.
For example:
static void Main(string[] args)
{
bool haveOpenCL = CvInvoke.HaveOpenCL;
bool haveOpenClGpu = CvInvoke.HaveOpenCLCompatibleGpuDevice;
CvInvoke.UseOpenCL = true;
Emgu.CV.Image<Bgr, Byte> lenaBgr = new Image<Bgr, Byte>(#"D:\OpenCV\opencv-3.2.0\samples\data\Lena.jpg");
CvInvoke.Imshow("Lena BSG", lenaBgr);
Bgr color = lenaBgr[100, 100];
Console.WriteLine("Bgr: {0}", color.ToString());
Emgu.CV.Image<Hsv, Byte> lenaHsv = new Image<Hsv, Byte>(#"D:\OpenCV\opencv-3.2.0\samples\data\Lena.jpg");
CvInvoke.Imshow("Lena HSV", lenaHsv);
Hsv colorHsv = lenaHsv[100, 100];
Console.WriteLine("HSV: {0}", colorHsv.ToString());
CvInvoke.WaitKey(0);
}
}
The result:
Bgr: [87,74,182]
HSV: [176,151,182]
Lena BGR Lena HSV
Okay I already found a way using some help from .NET framework
given a Bgr pixel ;
1- Converting the color to System.Drawing.Color :
System.Drawing.Color intermediate = System.Drawing.Color.FromArgb((int)pixel.Red, (int)pixel.Green, (int)pixel.Blue);
2- Constructing Hsv from the intermediate.
Hsv hsvPixel = new Hsv(intermediate.GetHue(), intermediate.GetSaturation(), intermediate.GetBrightness());
Cheers.

Categories

Resources