Comment ajouter le support de `accumulateWeighted` à OpenCV.js?

Sep 15 2020

Contexte: Ceci est lié à "Comment créer un opencv.js personnalisé avec opencv_contrib?" dans un sens général.

Cette question est une variante très spécifique: je voudrais utiliser à accumulateWeightedpartir du imgprocmodule avec OpenCV.js

Jusqu'à présent, ma tentative consistait à comprendre où se trouvent les choses et je peux donc essayer de modifier un peu la configuration emscripten. Pour autant que je sache, la plupart des fichiers avec lesquels je dois travailler vivent dans:

  • opencv/modules/js/src
  • opencv/platforms/js

Par exemple, je peux voir cette section dans opencv_js.config.py:

imgproc = {'': ['Canny', 'GaussianBlur', 'Laplacian', 'HoughLines', 'HoughLinesP', 'HoughCircles', 'Scharr','Sobel', \
                'adaptiveThreshold','approxPolyDP','arcLength','bilateralFilter','blur','boundingRect','boxFilter',\
                'calcBackProject','calcHist','circle','compareHist','connectedComponents','connectedComponentsWithStats', \
                'contourArea', 'convexHull', 'convexityDefects', 'cornerHarris','cornerMinEigenVal','createCLAHE', \
                'createLineSegmentDetector','cvtColor','demosaicing','dilate', 'distanceTransform','distanceTransformWithLabels', \
                'drawContours','ellipse','ellipse2Poly','equalizeHist','erode', 'filter2D', 'findContours','fitEllipse', \
                'fitLine', 'floodFill','getAffineTransform', 'getPerspectiveTransform', 'getRotationMatrix2D', 'getStructuringElement', \
                'goodFeaturesToTrack','grabCut','initUndistortRectifyMap', 'integral','integral2', 'isContourConvex', 'line', \
                'matchShapes', 'matchTemplate','medianBlur', 'minAreaRect', 'minEnclosingCircle', 'moments', 'morphologyEx', \
                'pointPolygonTest', 'putText','pyrDown','pyrUp','rectangle','remap', 'resize','sepFilter2D','threshold', \
                'undistort','warpAffine','warpPerspective','warpPolar','watershed', \
                'fillPoly', 'fillConvexPoly'],
           'CLAHE': ['apply', 'collectGarbage', 'getClipLimit', 'getTilesGridSize', 'setClipLimit', 'setTilesGridSize']}

Je peux simplement ajouter accumulateWeightedà la liste, mais je pense que cela devrait également être ajusté bindings.cpp/ core_bindings.cppcorrectement. C'est là que réside une certaine confusion lorsque j'apprends avec emscripten.

Par exemple en ajoutant:

// C++: void accumulateWeighted(InputArray src, InputOutputArray dst, double alpha, InputArray mask=noArray() )
void accumulateWeighted_wrapper(const cv::Mat& src, const cv::Mat& dst, double alpha, cv::Mat& mask) {
    return cv::accumulateWeighted(src, dst, alpha, mask);
}

void accumulateWeighted_wrapper_1(const cv::Mat& src, const cv::Mat& dst, double alpha) {
    return cv::accumulateWeighted(src, dst, alpha);
}
// ...
function("accumulateWeighted", select_overload<void(const cv::Mat&, const cv::Mat&, double , cv::Mat&)>(&Wrappers::accumulateWeighted_wrapper));

function("accumulateWeighted", select_overload<void(const cv::Mat&, const cv::Mat&, double)>(&Wrappers::accumulateWeighted_wrapper_1));

à bindings.cpp

Je ne sais pas si je manque autre chose? J'espère que les développeurs avec plus d'expérience OpenCV + emscripten pourront fournir des conseils.

Mise à jour J'ai compilé OpenCV.js à l'aide de Docker et essayé d'appeler cv.accumulateWeighted, mais j'obtiens une erreur:

cv.accumulateWeighted(src, dst, 0.001)
opencv.js:9 Uncaught 6587800
___resumeException  @   opencv.js:9
(anonymous) @   02086862:0x1621d4
(anonymous) @   02086862:0x1c1f8
dynCall_viid    @   02086862:0x365dc
dynCall_viiid   @   02086862:0x37296
Module.dynCall_viiid    @   opencv.js:9
dynCall_viiid_532   @   VM1966:4
accumulateWeighted  @   VM3269:10
proto.<computed>    @   opencv.js:9
(anonymous) @   VM5257:1

Je ne suis pas sûr à 100% de ce que j'ai mal. Voici un extrait de code qui comprend un lien vers le script compilé:

function onOpenCvReady(){
  cv.then(test);
}

function test(cv){
  console.log("cv",cv.getBuildInformation());
  
  src = cv.Mat.ones(3,3, cv.CV_8UC1);
  dst = cv.Mat.ones(3,3, cv.CV_8UC1);
  mask = cv.Mat.zeros(3,3, cv.CV_8UC1);


  console.log("dst before", dst.data);

// throws error
  try{
    cv.accumulateWeighted(src, dst, 0.001, mask);
  }catch(err){
    console.warn("error running accumulateWeighted")
    console.warn(err.stack)
  }
  console.log("dst after", dst);
}
<script async src="https://lifesine.eu/so/opencv_js_ubuntu/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>

Mise à jour J'ai mis à jour l'extrait ci-dessus pour utiliser OpenCV.js compilé sur Ubuntu. De plus, j'ai eu une faute de frappe dans les fonctions accumulateWeighted_wrapperet accumulateWeighted_wrapper_1, mais je reçois toujours une erreur très similaire qui me porte à croire qu'il y a quelque chose d'autre qui me manque dans le code des liaisons.

Quelle est la bonne façon d'ajouter la accumulateWeightedprise en charge d'OpenCV.js?

Réponses

GeorgeProfenza Oct 03 2020 at 09:22

Pour la portée de cette question, une solution de contournement consiste à ne pas modifier OpenCV.js et à recompiler, pour implémenter la fonctionnalité dans JS. La fonction comporte à peu près deux parties (et un gotcha):

  1. accumuler: ajouter une nouvelle image sur une image existante
  2. peser la nouvelle image inversement proportionnelle à l'ancienne image
  3. le catch utilise une image pour agir comme un accumulateur: sinon, il s'agit simplement d'interpoler / lerping / fondu enchaîné linéairement entre deux images:
cv.lerp = function(lerpFromMat, lerpToMat, lerpResult, amount){
    // TODO: args safety check (including constraining amount)
    if (lerpToMat.cols === 0) {
      lerpFromMat.copyTo(lerpResult);
    } else if (lerpFromMat.cols === 0) {
      lerpToMat.copyTo(lerpResult);
    } else {
      cv.addWeighted(lerpFromMat, amount, lerpToMat, 1.0 - amount, 0.0, lerpResult);
    }
  }

// super simplified alias, skipping mask for now
cv.accumulateWeighted = function(newMat, accumulatorMat, alpha){
   p5cv.lerp(accumulatorMat, newMat, accumulatorMat, alpha);
}

J'attends toujours avec impatience une autre solution générale: une ventilation du processus pour ajouter de nouvelles fonctions c ++ à OpenCV.js via emscripten (que ce soit accumulateWeighted ou autre chose)