From 1bb61fc38a3b143201b1b2507f9bb58f43f303d1 Mon Sep 17 00:00:00 2001 From: Pierre Colle Date: Wed, 23 Aug 2017 19:14:32 +0200 Subject: [PATCH] Histogram now takes multiple dimensions --- examples/calc-hist.js | 54 ++++++++++++++++++--- src/Histogram.cc | 109 ++++++++++++++++++++++++++++++++---------- 2 files changed, 131 insertions(+), 32 deletions(-) diff --git a/examples/calc-hist.js b/examples/calc-hist.js index bf7c81d..9025aff 100644 --- a/examples/calc-hist.js +++ b/examples/calc-hist.js @@ -9,19 +9,59 @@ cv.readImage('./files/car1.jpg', function(err, im) { var bgrPlanes = im.split(); - var size = 4, + var size = 256, range = [0, 256], uniform = true, accumulate = true, - histFile = 'files/chart.png'; + histFile = 'files/chart2.png'; /// Compute the histograms: - var bHist = cv.histogram.calcHist( bgrPlanes[0], size, range, uniform, accumulate ); - var gHist = cv.histogram.calcHist( bgrPlanes[1], size, range, uniform, accumulate ); - var rHist = cv.histogram.calcHist( bgrPlanes[2], size, range, uniform, accumulate ); - - console.log("Histograms are \n Blue : ", bHist, "\n Green : ", gHist, "\n Red : ", rHist); + var hist64 = cv.histogram.calcHist( im, [0, 1, 2], [4, 4, 4], [[0, 256], [0, 256], [0, 256]], uniform, accumulate ); + var bHist = cv.histogram.calcHist( im, [0], [size], [range], uniform, accumulate ); + var gHist = cv.histogram.calcHist( im, [1], [size], [range], uniform, accumulate ); + var rHist = cv.histogram.calcHist( im, [2], [size], [range], uniform, accumulate ); +////// +// Uncommentand run `npm install chartjs-node` to draw the histogram ! +/// +/* + var ChartjsNode = require('chartjs-node'); + var chartNode = new ChartjsNode(1200, 1200); + chartNode.drawChart({ + type: 'bar', + data: { + labels: bHist.map(function(a,i){return i.toString()}), + datasets : [{ + data : bHist, + backgroundColor : "#4183c4", + borderColor : "#0c4b8a", + label : 'Blue' + },{ + data : gHist, + backgroundColor : "#83c441", + borderColor : "#0c4b8a", + label : 'Green' + },{ + data : rHist, + backgroundColor : "#c44183", + borderColor : "#0c4b8a", + label : 'Red' + }] + }, + options: { + title: { + display: true, + text: 'RGB Histograms' + } + } + }).then(function(){ + return chartNode.writeImageToFile('image/png', histFile); + }).then(function(){ + console.log("result has been written in "+histFile) + }).catch(function(e){ + console.log("error",e) + }); +*/ }); diff --git a/src/Histogram.cc b/src/Histogram.cc index 72bbd9d..6c1ad97 100644 --- a/src/Histogram.cc +++ b/src/Histogram.cc @@ -20,43 +20,102 @@ NAN_METHOD(Histogram::CalcHist) { Matrix* m0 = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); cv::Mat inputImage = m0->mat; - // Arg 1 is histogram sizes in first dimension - /// Establish the number of bins - int histSize = info[1]->IntegerValue(); - - // Arg 2 is array of the histogram bin boundaries in each dimension - - Local nodeRange = Local::Cast(info[2]->ToObject()); - unsigned int num_range = nodeRange->Length(); - - /// Set the ranges ( for B,G,R) ) - float range[num_range]; - for (unsigned int i = 0; i < num_range; i++) { - range[i] = nodeRange->Get(i)->NumberValue(); + //int dims = 3; + // Arg 1 is the channel + Local nodeChannels = Local::Cast(info[1]->ToObject()); + const unsigned int dims = nodeChannels->Length(); + int channels[dims]; + for (unsigned int i = 0; i < dims; i++) { + channels[i] = nodeChannels->Get(i)->IntegerValue(); } - const float* histRange = { range }; - // Arg 3 is uniform flag - bool uniform = info[3]->BooleanValue(); + //int channels[] = {0, 1, 2}; - // Arg 4 is accumulate flag - bool accumulate = info[4]->BooleanValue(); + // Arg 2 is histogram sizes in each dimension + Local nodeHistSizes = Local::Cast(info[2]->ToObject()); + int histSize[dims]; + for (unsigned int i = 0; i < dims; i++) { + histSize[i] = nodeHistSizes->Get(i)->IntegerValue(); + } + // Arg 3 is array of the histogram bin boundaries in each dimension + + Local nodeRanges = Local::Cast(info[3]->ToObject()); + /// Set the ranges ( for B,G,R) ) + float histRanges[dims][2]; + + for (unsigned int i = 0; i < dims; i++) { + Local nodeRange = Local::Cast(nodeRanges->Get(i)->ToObject()); + float lower = nodeRange->Get(0)->NumberValue(); + float higher = nodeRange->Get(1)->NumberValue(); + histRanges[i][0] = lower; + histRanges[i][1] = higher; + } + + float first_range[] = { histRanges[0][0], histRanges[0][1] }; + float second_range[] = { 0, 0}; + float third_range[] = { 0, 0}; + + if(dims >= 2){ + second_range[0] = histRanges[1][0]; + second_range[1] = histRanges[1][1]; + } + if(dims >= 3){ + third_range[0] = histRanges[2][0]; + third_range[1] = histRanges[2][1]; + } + + const float* histRanges1[] = {first_range, second_range, third_range}; + + // Arg 4 is uniform flag + bool uniform = info[4]->BooleanValue(); + + // Arg 5 is accumulate flag + bool accumulate = info[5]->BooleanValue(); +/* + float rranges[] = { 0, 256 }; + float granges[] = { 0, 256 }; + float branges[] = { 0, 256 }; + + const float* histRange[] = { rranges, granges, branges}; +*/ // Make a mat to hold the result image cv::Mat outputHist; // Perform calcHist - cv::calcHist(&inputImage, 1, 0, cv::Mat(), outputHist, 1, &histSize, &histRange, uniform, accumulate); + cv::calcHist(&inputImage, 1, channels, cv::Mat(), outputHist, dims, histSize, histRanges1, uniform, accumulate); // Wrap the output image - //Local outMatrixWrap = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); - //Matrix *outMatrix = Nan::ObjectWrap::Unwrap(outMatrixWrap); - //outMatrix->mat = outputHist; + /*Local outMatrixWrap = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked(); + Matrix *outMatrix = Nan::ObjectWrap::Unwrap(outMatrixWrap); + outMatrix->mat = outputHist; - v8::Local arr = Nan::New(histSize); + info.GetReturnValue().Set(outMatrixWrap);*/ - for (unsigned int i=0; i < (unsigned int) histSize; i++) { - arr->Set(i, Nan::New(outputHist.at(i))); + v8::Local arr = Nan::New(histSize[0]); + + if(dims < 1 || dims > 3){ + return Nan::ThrowTypeError("OPENCV nodejs binding error : only dimensions from 1 to 3 are allowed"); + } + + for (unsigned int i=0; i < (unsigned int) histSize[0]; i++) { + if(dims <= 1){ + arr->Set(i, Nan::New(outputHist.at(i))); + } else { + v8::Local arr2 = Nan::New(dims); + for (unsigned int j=0; j < (unsigned int) histSize[1]; j++) { + if(dims <= 2){ + arr2->Set(j, Nan::New(outputHist.at(i,j))); + } else { + v8::Local arr3 = Nan::New(dims); + for (unsigned int k=0; k < (unsigned int) histSize[1]; k++) { + arr3->Set(k, Nan::New(outputHist.at(i,j,k))); + } + arr2->Set(j, arr3); + } + } + arr->Set(i, arr2); + } } info.GetReturnValue().Set(arr);