【问题标题】:How to Convert Python Code to Java without numpy如何在没有 numpy 的情况下将 Python 代码转换为 Java
【发布时间】:2019-10-20 18:45:33
【问题描述】:

我在 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,那也很棒。

【问题讨论】:

  • 不,你不能只在 Android 上运行 python。为此,您必须编写相关的 Java 代码。
  • @ZdaR 甚至不使用 Jython for Android 或 Qpython 吗?
  • 和无关的:坚持 java 命名约定。 Java 方法名应该是 camelCase()。另请注意,Java 没有“真正的”多维数组,因此在性能方面会出现(负面)惊喜。用 java 编写高性能的“计算代码”是可能的,但这就像它自己的科学。
  • @ZdaR 您知道如何在特定情况下执行此操作吗?我对 python 有点陌生,在 Java 方面不是最好的
  • @Corentin Jython 代码工作。但是不要忘记,像 numpy 这样的库从所有核心计算的东西……都用 C 实现的事实中汲取了它们的性能。所以,当你找到一种方法来为 Android 编译该库时,你也许有机会与 jython ;-)

标签: java android python arrays opencv


【解决方案1】:

此时,您应该考虑看看 SL4A 项目,它允许您通过 java 应用在 Android 上运行 Python 代码。

这里有一些有趣的链接:

  1. https://github.com/damonkohler/sl4a

  2. https://norwied.wordpress.com/2012/04/11/run-sl4a-python-script-from-within-android-app/

  3. http://jokar-johnk.blogspot.com/2011/02/how-to-make-android-app-with-sl4a.html

【讨论】:

    【解决方案2】:

    让我们看看这两个命令并尝试将它们转换为 Java API 调用。它可能不是简单的 2 行代码。

    mask = np.where((mask==2) | (mask == 0),0,1).astype('uint8')

    在上面的命令中,我们正在创建一个新的图像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)
    

    现在您需要将此前景蒙版与输入图像相乘,以获得最终的抓取图像:

    // 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);
    

    【讨论】:

      猜你喜欢
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      • 2018-02-25
      • 1970-01-01
      • 2022-06-26
      • 1970-01-01
      • 2020-02-06
      • 2022-07-07
      相关资源
      最近更新 更多