c++ - Resizing the image in C# and sending it to OpenCV results in distorted image -
this follow-up question related this one.
basically, have dll
uses opencv
image manipulation.
there 2 methods, 1 accepting image-path
, , other 1 accepting cv::mat
.
1 working image-path
works fine.
1 accepts image
problematic.
here method accepts filename(dll
):
cdll2_api void classify(const char * img_path, char* out_result, int* length_of_out_result, int n) { auto classifier = reinterpret_cast<classifier*>(gethandle()); cv::mat img = cv::imread(img_path); cv::imshow("img recieved c#", img); std::vector<predictionresults> result = classifier->classify(std::string(img_path), n); std::string str_info = ""; //... *length_of_out_result = ss.str().length(); }
here method accepts image(dll
) :
cdll2_api void classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, int step, char* out_result, int* length_of_out_result, int top_n_results) { auto classifier = reinterpret_cast<classifier*>(gethandle()); cv::mat img = cv::mat(height, width, cv_8uc3, (void*)img_pointer, step); std::vector<prediction> result = classifier->classify(img, top_n_results); //... *length_of_out_result = ss.str().length(); }
here code in c#
application : dll
import:
[dllimport(@"cdll2.dll", callingconvention = callingconvention.cdecl, charset = charset.ansi)] static extern void classify_image(intptr img, uint height, uint width, int step, byte[] out_result, out int out_result_length, int top_n_results = 2);
the method sends image dll
:
private string classify_usingimage(bitmap img, int top_n_results) { byte[] res = new byte[200]; int len; bitmapdata bmpdata; bmpdata = img.lockbits(new rectangle(0, 0, img.width, img.height), imagelockmode.readonly, img.pixelformat); classify_image(bmpdata.scan0, (uint)bmpdata.height, (uint)bmpdata.width, bmpdata.stride, res, out len, top_n_results); //remember unlock!!! img.unlockbits(bmpdata); string s = asciiencoding.ascii.getstring(res); return s; }
now, works when send image dll
. if use imshow()
show received image, image shown fine.
the actual problem :
however, when resize same image , send using same method above, image distorted.
i need add that, if resize image using given c# method below, save it, , pass filename dll
opened using classify(std::string(img_path), n);
works perfectly.
here screenshot showing example of happening:
image sent c#
without being resized :
when same image first resized , sent dll
:
here image first resized (in c#), saved disk , filepath
sent dll
:
this snippet responsible resizing (c#
):
/// <summary> /// resize image specified width , height. /// </summary> /// <param name="image">the image resize.</param> /// <param name="width">the width resize to.</param> /// <param name="height">the height resize to.</param> /// <returns>the resized image.</returns> public static bitmap resizeimage(image image, int width, int height) { var destrect = new rectangle(0, 0, width, height); var destimage = new bitmap(width, height); destimage.setresolution(image.horizontalresolution, image.verticalresolution); using (var graphics = graphics.fromimage(destimage)) { graphics.compositingmode = compositingmode.sourcecopy; graphics.compositingquality = compositingquality.highquality; graphics.interpolationmode = interpolationmode.highqualitybicubic; graphics.smoothingmode = smoothingmode.highquality; graphics.pixeloffsetmode = pixeloffsetmode.highquality; using (var wrapmode = new imageattributes()) { wrapmode.setwrapmode(wrapmode.tileflipxy); graphics.drawimage(image, destrect, 0, 0, image.width, image.height, graphicsunit.pixel, wrapmode); } } return destimage; }
and original image
this classify
method uses filepath read images:
std::vector<predictionresults> classifier::classify(const std::string & img_path, int n) { cv::mat img = cv::imread(img_path); cv::mat resizedimage; std::vector<predictionresults> results; std::vector<float> output; // cv::imshow((std::string("img classify path") + type2str(img.type())), img); if (isresizedenabled()) { resizeimage(img, resizedimage); output = predict(resizedimage); } else { output = predict(img); img.release(); } n = std::min<int>(labels_.size(), n); std::vector<int> maxn = argmax(output, n); (int = 0; < n; ++i) { int idx = maxn[i]; predictionresults r; r.label = labels_[idx]; r.accuracy = output[idx]; results.push_back(r); } return results; }
and resizeimage
used in method above :
void classifier::resizeimage(const cv::mat & source_image, cv::mat& resizedimage) { size size(getresizeheight(), getresizeheight()); cv::resize(source_image, resizedimage, size);//resize image check(!resizedimage.empty()) << "unable decode image "; }
problem 2:
distortion after resizing aside, facing discrepancy between resizing in c#
, resizing using opencv
itself.
have created method using emgucv
(also given below) , passed needed information , did not face such distortions happen when resize image in c#
, send dll
.
however, discrepancy made me want understand causing these issues.
here method uses emgucv.mat
code works irrespective of resizing:
private string classify_usingmat(string imgpath, int top_n_results) { byte[] res = new byte[200]; int len; emgu.cv.mat img = new emgu.cv.mat(imgpath, imreadmodes.color); if (chkresizeimagecshap.checked) { cvinvoke.resize(img, img, new size(256, 256)); } classify_image(img.datapointer, (uint)img.height, (uint)img.width, img.step, res, out len, top_n_results); string s = asciiencoding.ascii.getstring(res); return s; }
why care?
because, different accuracy when use opencv
resize (both when use emgucv
's cvinvoke.resize()
, cv::resize()
) resizing image in c#, saving disk , send image path opencv
.
either need fix distortion happening when deal images in c#, or need understand why resizing in opencv has different results c# resizing.
so summarize issues , points made far :
- all situations intact, if resize image inside c# application, , pass info did before, image distorted (example given above)
- if resize image, save disk, , give filename
opencv
create newcv::mat
, works without issues. - if use
emugcv
, instead of workingbitmap
, useemug.cv.mat
, send needed parameters using mat object c#, no distortion happens. however, accuracy resized imagec#
( see#2
), different 1 resized image usingopencv
. doesn't make difference if resize image before hand usingcvinvoke.resize()
c#
, , send resulting image dll, or send original image (usingemgucv
) , resizing incpp
code usingcv::resize()
. prevents me usingemgucv
or passing image original image , resizing insidedll
usingopencv
.
here images different results, showing issues :
--------------------no resizing------------------------------ 1.using bitmap-no resize, =>safe, acc=580295 2.using emgu.mat-no resize =>safe, acc=0.580262 3.using filepath-no resize, =>safe, acc=0.580262 --------------------resize in c#------------------------------ 4.using bitmap-csharp resize, =>unsafe, acc=0.770425 5.using emgu.mat-emguresize, =>unsafe, acc=758335 6.**using filepath-csharp resize, =>unsafe, acc=0.977649** --------------------resize in dll------------------------------ 7.using bitmap-dll resize, =>unsafe, acc=0.757484 8.using emgu.dll resize, =>unsafe, acc=0.758335 9.using filepath-dll resize, =>unsafe, acc=0.758335
i need accuracy @ #6. can see emgucv
resize , opencv
resize function used in dll
, act similar , don't work expected(i.e. #2)!, c# resize method applied on image problematic, while if resized, saved , filename passed, result fine.
you can see screen shots depicting different scenarios here : http://imgur.com/a/xbgiq
ok.thanks dear god , great helps @edchum, work.! did use imdecode
@edchum suggested. how functions in dll
, c#
:
#ifdef cdll2_exports #define cdll2_api __declspec(dllexport) #else #define cdll2_api __declspec(dllimport) #endif #include "classification.h" extern "c" { cdll2_api void classify_image(unsigned char* img_pointer, long data_len, char* out_result, int* length_of_out_result, int top_n_results = 2); //... }
the actual method :
cdll2_api void classify_image(unsigned char* img_pointer, long data_len, char* out_result, int* length_of_out_result, int top_n_results) { auto classifier = reinterpret_cast<classifier*>(gethandle()); vector<unsigned char> inputimagebytes(img_pointer, img_pointer + data_len); cv::mat img = imdecode(inputimagebytes, cv_load_image_color); cv::imshow("img recieved c#", img); std::vector<prediction> result = classifier->classify(img, top_n_results); //... *length_of_out_result = ss.str().length(); }
here c# dll import:
[dllimport(@"cdll2.dll", callingconvention = callingconvention.cdecl, charset = charset.ansi)] static extern void classify_image(byte[] img, long data_len, byte[] out_result, out int out_result_length, int top_n_results = 2);
and actual method sending image dll:
private string classify_usingimage(bitmap image, int top_n_results) { byte[] result = new byte[200]; int len; bitmap img; if (chkresizeimagecshap.checked) img = resizeimage(image, int.parse(txtwidth.text), (int.parse(txtheight.text))); else img = image; //this situations, image not read disk, , stored in memort(e.g. image comes camera or snapshot) imageformat fmt = new imageformat(image.rawformat.guid); var imagecodecinfo = imagecodecinfo.getimageencoders().firstordefault(codec => codec.formatid == image.rawformat.guid); if (imagecodecinfo == null) { fmt = imageformat.jpeg; } using (memorystream ms = new memorystream()) { img.save(ms, fmt); byte[] image_byte_array = ms.toarray(); classify_image(image_byte_array, ms.length, result, out len, top_n_results); } return asciiencoding.ascii.getstring(result); }
by doing after resizing image c#, dont face distortions @ all. couldnt however, figure out why resize on opencv part wouldnt work expected!
Comments
Post a Comment