如何在不使用numpy的情况下将Python代码转换为Java

3

我在Python中有一个使用OpenCV从图像中去除背景的方法。 我希望在android的OpenCV版本中具有相同的功能,但我似乎无法理解数组的工作原理以及如何处理它们。

以下是我目前在Java中拥有的代码:

private Bitmap GetForeground(Bitmap source){
        source = scale(source,300,300);
        Mat mask = Mat.zeros(source.getHeight(),source.getWidth(),CvType.CV_8U);
        Mat bgModel = Mat.zeros(1,65,CvType.CV_64F);
        Mat ftModel = Mat.zeros(1,65,CvType.CV_64F);
        int x = (int)Math.round(source.getWidth()*0.1);
        int y = (int)Math.round(source.getHeight()*0.1);
        int width = (int)Math.round(source.getWidth()*0.8);
        int height = (int)Math.round(source.getHeight()*0.8);
        Rect rect = new Rect(x,y, width,height);
        Mat sourceMat = new Mat();
        Utils.bitmapToMat(source, sourceMat);
        Imgproc.grabCut(sourceMat, mask, rect, bgModel, ftModel, 5, Imgproc.GC_INIT_WITH_RECT);

        int frameSize=sourceMat.rows()*sourceMat.cols();
        byte[] buffer= new byte[frameSize];
        mask.get(0,0,buffer);
        for (int i = 0; i < frameSize; i++) {
            if (buffer[i] == 2 || buffer[i] == 0){
                buffer[i] = 0;
            }else{
                buffer[i] = 1 ;
            }
        }

        byte[][] sourceArray = getMultiChannelArray(sourceMat);
        byte[][][] reshapedMask = ReshapeArray(buffer, sourceMat.rows(), sourceMat.cols());
        return source;
    }

    private byte[][][] ReshapeArray(byte[] arr, int rows, int cols){
        byte[][][] out = new byte[cols][rows][1];
        int index=0;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                out[i][j][0] = arr[index];
                index++;
            }
        }
        return out;
    }

    public static byte[][] getMultiChannelArray(Mat m) {
        //first index is pixel, second index is channel
        int numChannels=m.channels();//is 3 for 8UC3 (e.g. RGB)
        int frameSize=m.rows()*m.cols();
        byte[] byteBuffer= new byte[frameSize*numChannels];
        m.get(0,0,byteBuffer);

        //write to separate R,G,B arrays
        byte[][] out=new byte[frameSize][numChannels];
        for (int p=0,i = 0; p < frameSize; p++) {
            for (int n = 0; n < numChannels; n++,i++) {
                out[p][n]=byteBuffer[i];
            }
        }
        return out;
    }

我想要重建的Python代码:

image = cv2.imread('Images/handheld.jpg')
image = imutils.resize(image, height = 300)
mask = np.zeros(image.shape[:2],np.uint8)
bgModel = np.zeros((1,65),np.float64)
frModel = np.zeros((1,65),np.float64)
height, width, d = np.array(image).shape
rect = (int(width*0.1),int(height*0.1),int(width*0.8),int(height*0.8))
cv2.grabCut(image, mask, rect, bgModel,frModel, 5,cv2.GC_INIT_WITH_RECT)
mask = np.where((mask==2) | (mask == 0),0,1).astype('uint8')
image = image*mask[:,:,np.newaxis]

我不知道如何转换Python代码的最后两行。如果有一种方法可以在我的项目中仅在Android设备上运行Python Clean,那将非常棒。


不,你不能在安卓上直接运行Python。你必须编写相关的Java代码以实现此目的。 - ZdaR
1
与此无关:遵循Java命名规范。Java方法名称应该采用驼峰式写法()。另外请注意,Java没有“真正的”多维数组,因此可能会有(负面)意外的性能问题。在Java中编写高性能的“计算代码”是可能的,但那就像一门科学。 - GhostCat
@Corentin Jython代码可以工作。但是不要忘记像numpy这样的库从其所有核心计算部分都是用C实现来获得性能的。因此,当您找到一种方法将该库编译为Android时,您可能有机会使用jython;-) - GhostCat
@Corentin 我现在并不太担心性能问题。我只是想看看它是否能工作。 - MrStruggles
@GhostCat 完全同意 :-) 但是,就像他没有谈论性能一样,这些解决方案浮现在我的脑海中。但是,用Java实现这个解决方案肯定会更快。 - user8007559
显示剩余2条评论
2个回答

1
让我们看一下这两个命令,并尝试将它们转换为Java API调用。这可能不是简单的2行代码。
在上述命令中,我们正在创建一个新图像mask,其像素值具有uint数据类型。新的mask矩阵在先前的mask具有20值的每个位置上都将具有值0,否则为1。让我们通过示例演示这一点:
mask = [
[0, 1, 1, 2],
[1, 0, 1, 3],
[0, 1, 1, 2],
[2, 3, 1, 0],
]

这个操作后的输出将会是:
mask = [
[0, 1, 1, 0],
[1, 0, 1, 1],
[0, 1, 1, 0],
[0, 1, 1, 0],
]

所以,上述命令只是生成一个只包含0和1值的二进制掩码。在Java中可以使用Core.compare()方法来复制此操作:
// Get a mask for all `1` values in matrix.
Mat mask1vals;
Core.compare(mask, new Scalar(1), mask1vals, Core.CMP_EQ);

// Get a mask for all `3` values in matrix.
Mat mask3vals;
Core.compare(mask, new Scalar(3), mask3vals, Core.CMP_EQ);

// Create a combined mask
Mat foregroundMask;
Core.max(mask1vals, mask3vals, foregroundMask)

现在,您需要将此前景掩模与输入图像相乘,以获得最终的GrabCut图像,如下所示:
// First convert the single channel mat to 3 channel mat
Imgproc.cvtColor(foregroundMask, foregroundMask, Imgproc.COLOR_GRAY2BGR);
// Now simply take min operation
Mat out;
Core.min(foregroundMask, image, out);

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接