code: @Override
      protected ImageWritable doTransform(ImageWritable image, Random random) {
          if (image == null) {
              return null;
          }
          Mat mat = converter.convert(image.getFrame());
          Point2f src = new Point2f(4);
          Point2f dst = new Point2f(4);
          src.put(0, 0, mat.cols(), 0, mat.cols(), mat.rows(), 0, mat.rows());
  
          for (int i = 0; i < 8; i++) {
              dst.put(i, src.get(i) + deltas[i] * (random != null ? 2 * random.nextFloat() - 1 : 1));
          }
          Mat result = new Mat();
          M = getPerspectiveTransform(src, dst);
          warpPerspective(mat, result, M, mat.size(), interMode, borderMode, borderValue);
  
          return new ImageWritable(converter.convert(result));
      }
docs: Takes an image and returns a transformed image.
  Uses the random object in the case of random transformations.
  
  @param image  to transform, null == end of stream
  @param random object to use (or null for deterministic)
  @return transformed image