Friday, August 24, 2018

Playing with OpenCV : dynamic magnification



I have been playing around with OpenCV (https://docs.opencv.org/3.3.0/index.html) on Android quite a bit these days. While I am using OpenCV for image processing and image recognition work (using caffe bridge), I wanted to implement a UX scenario with dynamic magnification when a user is interacting with an image. An example of this UX is seen below:



You can see this kind of UX on iOS when trying to select a text. This is the equivalent for selecting a part of the image. After trying out a bit, I figured we could do with some simple lines of code as follows:

  Mat img = ...; // the source image is read into this Mat
 int sz = .. ; // size of zoomed area in pixels
 int sf = 2 ;  // the scale factor
 int scaledFactor = sz * sf; // this would be the total width of the zoomed area            
  int mxX =  mnX + scaledFactor;
 int mxY =  mnY + scaledFactor;

 // the centre of the circle depicting the zoom
 Point circleCenter = new Point((mxX-mnX)/2, (mxY-mnY)/2);

 // the source rectangle 
 Rect rect = new Rect(mnHX, mnHY, sz, sz);
 // the scaled rectangle 
 Rect scaledRect = new Rect(mnX, mnY, scaledFactor, scaledFactor);
 Mat roiFrame = new Mat(img, rect);  // get the are of interest to magnify 
 Mat scaledFrame = new Mat(roiFrame.rows()*sf, roiFrame.cols()*sf, img.type());
 Mat circleMask = new Mat(roiFrame.rows()*sf, roiFrame.cols()*sf, img.type());
 // create a circular mask 
 rectangle(circleMask, new Point(0, 0), new Point(scaledFactor, scaledFactor), BLACK, -1);
 circle(circleMask, circleCenter, sz, WHITE, -1);
 // zoom the rectangular area
 resize(roiFrame, scaledFrame, new Size(), sf, sf, INTER_LINEAR);
 // now copy the zoomed area into the source image applying the circular mask 
 scaledFrame.copyTo(img.submat(scaledRect), circleMask);
 // indicative circle
 circle(img, new Point((mxX+mnX)/2, (mxY+mnY)/2), sz, GREEN, 1);

 // cleanup ..
 roiFrame.release();
 scaledFrame.release();
 circleMask.release();

The above code is essentially a fast way to get a source rectangular area on the screen where a user is interacting, scale that area to a factor as needed, then apply a circular mask to give an effect of magnifying glass, then copy this back on to the source image so that it overlays to give a smooth UX with dynamic magnification when selecting a portion of the image.

No comments: