Add step to Mat constructor when dataptr is not null
Closed this issue · 6 comments
Hello, if you see in opencv documentation, between all the Mat constructors there are three with a "Data" parameter, those three constructors add at the end a "Step" parameter. I think therefore in:
function pCvMatCreate(const ndims: Integer; const dims: PInteger; const mtype: integer; dataptr: UInt64 = 0): PCvMat_t; cdecl;
It should be a last "Step" parameter also.
Hello, I will study the exact meaning of this parameter, and how it can be added to wrapper constructors.
Remember that Mat has a bunch of constructors and methods; not all of them are translated in the wrapper. Because many constructors, functions/methods, are used only internally from Opencv. So there is no interest to expose them in wrapper.
Hello, thanks. This issue stems from the colorization example. In your Delphi colorization example, outcome colorImg is good when you show it in pCvimshow, but if I try to convert it with MatImage2Bitmap the resulting bitmap is black. I implemented this same example in C++ and I converted the outcome Mat to a bitmap with a different method that uses precisely a temporal Mat constructed with these issue parameters, thus my interest in it. So I think in this particular case the constructor is not only to Opencv internal use. I think Step parameter is what is called "Stride" in Microsoft win api documentation, but I am not totally sure of that.
Ok, I will examine the colorization example.
The original C++ colorization sample program has these lines:
Size siz(result.size[2], result.size[3]);
Mat a = Mat(siz, CV_32F, result.ptr(0,0));
Mat b = Mat(siz, CV_32F, result.ptr(0,1));
Note that there is no fourth "step" parameter in constructors. The default value
AUTO_STEP is used. Constructor signature:
Mat (Size size, int type, void *data, size_t step=AUTO_STEP)
So I think there is no need of step parameter for this case. Although
adding it could create a more complete translation of that Mat constructor.
The problem is that colorImg is a type CV_32F Mat, that is every pixel is a float number, not a byte (CV_8U).
The Opencv function "imshow" automatically does the conversion, but in other cases the conversion has to
be explicit.
For example, the save function "imwrite" doesn't do implicit conversion.
You can add these lines:
..............
pCvimshow(@cvstr, img); // existing line
// -------- new lines ----------------------------
pCvMatConvertTo(colorImg, colorImg, CV_8U, 255); // conversion to bytes
cvstr.pstr:=PAnsiChar('c:\temp\colorized.bmp'); // or Jpg or Png or whatever supported type
pCvimwrite(@cvstr, colorImg);
The saved image is ok. Without the conversion to bytes, it's all black.
So, before converting to BMP, or any other manipulation, you have to convert to bytes.
Ok, thanks, I tried the same conversion but without the 255 as last parameter so it took the default value, that it seems is 1.0, this did the trick. Anyway, as you say, implementing the step would be good, and I don't think it would be particularly hard, but as you wish, many thanks for the code, regards. (You can close this if you want).
Yes, the default value of fourth parameter in PcvMatConvertTo is 1.0.
The 255 constant derives from the initial call to PcvMatConvertTo, where the scale parameter was 1/255, so for the inverse conversion the parameter should be 255.
Indeed saving image doesn't work without 255 value.
And doesn't work neither converting to Bmp and saving to file, as this:
pCvMatConvertTo(colorImg, colorImg, CV_8U); // conversion to bytes without 255
bmp:=TBitmap.Create;
bmp.pixelformat:=pf24bit;
MatImage2Bitmap(colorImg, bmp);
bmp.SaveToFile('c:\temp\test.bmp'); // black image
bmp.Free;
So 255 value is mandatory.
Of course I am modifying dnnRecolorize program, using Delphi XE2 32 bit on Windows 11.
Maybe your language/os/program are different .