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
opencvcreate 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 incppcode usingcv::resize(). prevents me usingemgucvor passing image original image , resizing insidedllusingopencv.
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