Search code examples
javaopencvmat

Java OpenCV Layer small image onto larger image with transparency


I am trying to write a function that overlays an image at a rectangle with transparency over top of another image, However it doesn't layer the images it just erases the section that I overlay and the transparency cuts through the entire image. Here is my code.

public static void overlayImage(String imagePath, String overlayPath, int x, int y, int width, int height) {
    Mat overlay = Imgcodecs.imread(overlayPath, Imgcodecs.IMREAD_UNCHANGED);
    Mat image = Imgcodecs.imread(imagePath, Imgcodecs.IMREAD_UNCHANGED);

    Rectangle rect = new Rectangle(x, y, width, height);
    Imgproc.resize(overlay, overlay, rect.size());
    Mat submat = image.submat(new Rect(rect.x, rect.y, overlay.cols(), overlay.rows()));
    overlay.copyTo(submat);
    Imgcodecs.imwrite(imagePath, image);
}

EDIT: Here are some example pictures: Before:

enter image description here

After:

enter image description here


Solution

  • Found this function that does exactly what I needed.

     public static void overlayImage(Mat background,Mat foreground,Mat output, Point location){
    
      background.copyTo(output);
    
      for(int y = (int) Math.max(location.y , 0); y < background.rows(); ++y){
    
       int fY = (int) (y - location.y);
    
       if(fY >= foreground.rows())
              break;
    
          for(int x = (int) Math.max(location.x, 0); x < background.cols(); ++x){
              int fX = (int) (x - location.x);
              if(fX >= foreground.cols()){
               break;
              }
    
               double opacity;
               double[] finalPixelValue = new double[4];
    
               opacity = foreground.get(fY , fX)[3];
    
               finalPixelValue[0] = background.get(y, x)[0];
               finalPixelValue[1] = background.get(y, x)[1];
               finalPixelValue[2] = background.get(y, x)[2];
               finalPixelValue[3] = background.get(y, x)[3];
    
               for(int c = 0;  c < output.channels(); ++c){
                   if(opacity > 0){
                       double foregroundPx =  foreground.get(fY, fX)[c];
                       double backgroundPx =  background.get(y, x)[c];
    
                       float fOpacity = (float) (opacity / 255);
                       finalPixelValue[c] = ((backgroundPx * ( 1.0 - fOpacity)) + (foregroundPx * fOpacity));
                       if(c==3){
                           finalPixelValue[c] = foreground.get(fY,fX)[3];
                       }
                   }
               }
               output.put(y, x,finalPixelValue);
          }
      } 
    }