I'm using the EmguCV 3.0.0 wrapper to the OpenCV 3.0 library. I'm using the Mat
class in a few places. Here's an example of a single channel, 8x8 image made of double
values:
Mat image = new Mat(8, 8, DepthType.Cv64F, 1);
The Image<>
class provides reasonable means for getting and setting pixel values, and the method is identical for the Matrix<>
class, but it doesn't seem as obvious for the Mat
class. The only way I've figured out how to set individual pixel is using a mask:
// set two pixel values, (0,0) to 9.0, (2, 3) to 42.0
Matrix<byte> mask = new Matrix<byte>(8,8);
mask.Data[0, 0] = 1;
image.SetTo(new MCvScalar(9.0), mask);
mask = new Matrix<byte>(8,8);
mask.Data[2, 3] = 1;
image.SetTo(new MCvScalar(42.0), mask);
This is feels like it should be two lines, not six, so I feel like I'm missing something. Things get even more complicated when the Mat
is more than one channel, because Matrix<>
is only 2D, so the mask must be used to set the pixel on each channel.
I cannot afford the time or memory to set pixels this way. How can I set pixels with a single method call?
You can get elements from Mat by copying unmanaged memory blocks using DataPointer and converting managed to unmanaged types. Setting values is marshaling in the opposite direction.
For an example you can use such an extension class
public static class MatExtension
{
public static dynamic GetValue(this Mat mat, int row, int col)
{
var value = CreateElement(mat.Depth);
Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 1);
return value[0];
}
public static void SetValue(this Mat mat, int row, int col, dynamic value)
{
var target = CreateElement(mat.Depth, value);
Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 1);
}
private static dynamic CreateElement(DepthType depthType, dynamic value)
{
var element = CreateElement(depthType);
element[0] = value;
return element;
}
private static dynamic CreateElement(DepthType depthType)
{
if (depthType == DepthType.Cv8S)
{
return new sbyte[1];
}
if (depthType == DepthType.Cv8U)
{
return new byte[1];
}
if (depthType == DepthType.Cv16S)
{
return new short[1];
}
if (depthType == DepthType.Cv16U)
{
return new ushort[1];
}
if (depthType == DepthType.Cv32S)
{
return new int[1];
}
if (depthType == DepthType.Cv32F)
{
return new float[1];
}
if (depthType == DepthType.Cv64F)
{
return new double[1];
}
return new float[1];
}
}
Then getting and setting value is possible by single method call
var row = 2;
var col = 1;
var mat = new Mat(3, 3, DepthType.Cv64F, 3);
mat.SetValue(row, col, 3.14);
var value = mat.GetValue(row, col);
Tests with 200000000 operations shows that dynamic type version can be up to ~2.5x slower than static.
public static double GetDoubleValue(this Mat mat, int row, int col)
{
var value = new double[1];
Marshal.Copy(mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, value, 0, 1);
return value[0];
}
public static void SetDoubleValue(this Mat mat, int row, int col, double value)
{
var target = new[] { value };
Marshal.Copy(target, 0, mat.DataPointer + (row * mat.Cols + col) * mat.ElementSize, 1);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With