无法在Opencv jni android studio中传递Mat对象

时间:2018-01-19 11:44:12

标签: android c++ opencv image-processing android-ndk

我正在处理我的项目,这是关于Android应用程序中的文档阴影删除。我尝试通过使用按钮来处理输入图像以删除阴影来修改c ++算法到android但仍然有一些错误我没有理想的解决方法,因为我不擅长编码这里是我的代码项目

MainActivity.java

public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.
static {
    System.loadLibrary("native-lib");
    System.loadLibrary("opencv_java3");
}

public static String TAG ="MainActivity";

ImageView imageView;
Button loadImage;
Button process;
private int  REQUEST_CODE = 1;
Mat image = new Mat();
Bitmap bitmap;
Bitmap bmp;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    imageView = (ImageView) findViewById(R.id.imageView);
    loadImage = (Button) findViewById(R.id.button);
    process = (Button) findViewById(R.id.button2);

    loadImage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent();
            intent.setType("image/");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent,"Select Image"),REQUEST_CODE);
        }
    });

   process.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            image = new Mat (bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1);
            Utils.bitmapToMat(bitmap, image);
            Native.removeShadow(image.getNativeObjAddr());
            Utils.matToBitmap(image,bitmap);
            imageView.setImageBitmap(bitmap);
        }
    });
}
@Override
protected void onActivityResult(int request_code, int result_code, Intent data){
    super.onActivityResult(request_code,result_code,data);
    if(request_code == REQUEST_CODE && result_code == RESULT_OK && data != null && data.getData() != null ){
        Uri uri = data.getData();
        try{
            bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
            imageView.setImageBitmap(bitmap);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

}

Nativa.java

public class Native {
public native static void removeShadow (long addrRgba);

} shadowRemove.h

#include "jni.h"
#include <stdio.h>
#include <iostream>
#include <omp.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ml/ml.hpp>
#include <opencv2/photo/photo.hpp>
#include <cmath>
#include <random>

#ifndef SHADOWDOCTEST_SHADOWREMOVE_H
#define SHADOWDOCTEST_SHADOWREMOVE_H

#define BUFFER_SIZE 1000
#define USE_SAMPLING 1

using namespace cv;
using namespace std;
using namespace cv::ml;
extern "C" {
JNIEXPORT void JNICALL Java_com_example_shadowdoctest_Native_removeShadow(JNIEnv *, jclass, jlong);

void removeShadow(Mat& img);

// Returns the block centered around (x,y).
bool GetBlock(int x, int y, Mat &block, Mat &dsImage);

void ClusterBlock(Mat &block, Mat &clusterMu, int *randInd);

// Identifies the local cluster belonging to the background and saves it in the shadow map
// Currently uses max cluster mean.
void CalculatePaperStatistics(int x, int y, Mat &clusterMu);

// Finds the block that best represents the background region. Used for constructing the
// shadow map (gain map)
void FindReferenceIndex(int &refInd, Mat &dsImage, Vec3f &ref);

void NormalizeShadowMap(int refIndex, Vec3f &ref);

void UpsampleShadowMap();

void ApplyShadowMap();

// Converts x and y index to access downsampled images (xhat = x and
// yhat = y when stride is 1)
void ConvertIndex(int x, int y, int &xHat, int &yHat);


// Input image, shadow map (gain map), and mask of image regions
Mat *image;
Mat *shadowMap;

// Full width, height, and number of channels
int width;
int height;
int channels;

// Number of pixels to skip when performing local analysis
int stride;

// Size of overlapping blocks in local analysis
int blockSize;

// Number of clusters used for local analysis (i.e., 2)
int numOfClusters;

// Number of clusters used for global analysis (i.e., 3)
int numOfClustersRef;

// Maximum number of iterations and epsilon threshold used as stopping condition for GMM clustering
int maxIters;
float emEps;

// Amount of downsampling to be used on the original image (for speedup)
float dsFactor;

// Number of local and global samples in the block and image, respectively (Default is 150 and 1000)
int numOfLocalSamples;
int numOfGlobalSamples;
}
#endif //SHADOWDOCTEST_SHADOWREMOVE_H

shadowRemove.cpp

#include "shadowRemove.h"
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstring>


JNIEXPORT void JNICALL Java_com_example_shadowdoctest_Native_removeShadow(JNIEnv *, jclass, jlong addrRgba){
    Mat& image = *(Mat*)addrRgba;

    removeShadow(image);
}

void removeShadow(Mat& img){
    image = new Mat(img);
   // image.convertTo(image, CV_32FC3);
    width = image->cols;
    height = image->rows;
    channels = image->channels();

    stride = 20; // Number of pixels to skip when performing local analysis
    blockSize = 21; // Size of overlapping blocks in local analysis
    numOfClusters = 3; // Number of clusters used for local analysis
    numOfClustersRef = 3; // Number of clusters used for global analysis
    maxIters = 100; // Maximum number of iterations used as stopping condition for GMM clustering.
    emEps = 0.1f; // Epsilon threshold used as stopping condition for GMM clustering.
    dsFactor = 1.0f; // No downsampling is done
    numOfLocalSamples = 150; // Number of samples to take in each block (for local statistics)
    numOfGlobalSamples = 1000; // Number of samples to take throughout entire image (for global statistics)

    int sHeight, sWidth;

    shadowMap = new Mat(image->cols, image->rows, CV_32FC3, CV_RGB(-1, -1, -1));//CV_32FC3 is a three channel matrix of 32-bit floats
    resize(*shadowMap, *shadowMap, Size(0, 0), dsFactor, dsFactor, INTER_LANCZOS4);
    ConvertIndex(shadowMap->cols, shadowMap->rows, sWidth, sHeight);
    resize(*shadowMap, *shadowMap, Size(sWidth, sHeight));

    int threadCount = omp_get_max_threads();
    Mat* blockList = new Mat[threadCount];
    for (int i = 0; i < threadCount; i++) {
        blockList[i] = Mat(height, width, CV_32FC3, CV_RGB(0, 0, 0));
    }
    Mat dsMask = Mat(shadowMap->rows, shadowMap->cols, CV_8UC1, Scalar(0));

    int* randInd = new int[numOfLocalSamples];
    int size = blockSize * blockSize; // TODO: use size_t
    vector<int> freeIndexes;
    for (int i = 0; i < size; i++) {
        freeIndexes.push_back(i);
    }
    int count = 0;
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(0, size);
    while (count < numOfLocalSamples) {
        int indexCandidate = distribution(generator);
        vector<int>::iterator it = std::find(freeIndexes.begin(), freeIndexes.end(), indexCandidate);
        if (it != freeIndexes.end()) {
            randInd[count] = indexCandidate;
            freeIndexes.erase(it);
            count++;
        }
    }
    Mat dsImage;
    resize(*image, dsImage, Size(0, 0), dsFactor, dsFactor, INTER_NEAREST);
    width = dsImage.cols;
    height = dsImage.rows;

#pragma omp parallel
    {
#pragma omp for schedule(dynamic) nowait
        for (int i = 0; i < height; i += stride) {
            for (int j = 0; j < width; j += stride) {

                // Get current block
                int threadNum = omp_get_thread_num();
                Mat& curBlock = blockList[threadNum];
                if (GetBlock(j, i, curBlock, dsImage)) {

                    // Cluster pixel intensities
                    Mat curMu;
                    vector<Mat> listOfCovs;
                    ClusterBlock(curBlock, curMu, randInd);

                    // Find paper mu of current block and update global matrix
                    CalculatePaperStatistics(j, i, curMu);

                }

            }
        }
    }
    delete[] randInd;
    delete[] blockList;
    int refIndex = -1;
    Vec3f ref;
    FindReferenceIndex(refIndex, dsImage, ref);
    width = image->cols;
    height = image->rows;

    medianBlur(*shadowMap, *shadowMap, 3);
    GaussianBlur(*shadowMap, *shadowMap, Size(3, 3), 2.5f);
    Mat dsShadowMap = *shadowMap;
    UpsampleShadowMap();

    NormalizeShadowMap(refIndex, ref);
    ApplyShadowMap();
}
bool GetBlock (int x, int y, Mat& block, Mat& dsImage) {
    int halfBlock = (int) floorf(float(blockSize) / 2.0f);
    int minX = max(0, x - halfBlock);
    int maxX = min(width - 1, x + halfBlock);
    int minY = max(0, y - halfBlock);
    int maxY = min(height - 1, y + halfBlock);
    int deltaY = maxY - minY + 1;
    int deltaX = maxX - minX + 1;

    if (block.rows != deltaY || block.cols != deltaX) {
        block = Mat(deltaY, deltaX, CV_32FC3, CV_RGB(0, 0, 0));
    }

    // Copy intensities to block
    int bX = 0;
    int bY = 0;
    for (int i = minY; i <= maxY; i++) {
        for (int j = minX; j <= maxX; j++) {
            for (int k = 0; k < channels; k++) {
                block.at<Vec3f>(bY, bX)[k] = dsImage.at<Vec3f>(i, j)[k];
            }
            bX++;
        }
        bX = 0;
        bY++;
    }

    return true;
}
void ClusterBlock (Mat& block, Mat& clusterMu, int* randInd) {

    // Set up expectation maximization model
    Ptr<EM> emModel = EM::create();
    emModel->setClustersNumber(numOfClusters);
    emModel->setCovarianceMatrixType(EM::COV_MAT_DIAGONAL);
    emModel->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, maxIters, emEps));

    // Cluster block with k means initializer
    Mat samples;
    if (block.rows * block.cols == blockSize * blockSize) {
        Mat tmp(numOfLocalSamples, 1, CV_32FC3, CV_RGB(-1, -1, -1));
        for (int i = 0; i < numOfLocalSamples; i++) {
            assert(randInd[i] >= 0 && randInd[i] < block.rows * block.cols);
            tmp.at<Vec3f>(i) = block.at<Vec3f>(randInd[i]);
        }
        samples = tmp.reshape(1);
    }
    else {
        samples = block.reshape(0, block.rows * block.cols);
        samples = samples.reshape(1);
    }
    emModel->trainEM(samples);

    clusterMu = emModel->getMeans();
    clusterMu = clusterMu.reshape(channels);
    clusterMu.convertTo(clusterMu, CV_32FC3);

}

void CalculatePaperStatistics(int x, int y, Mat& clusterMu) {
    int sX, sY;
    ConvertIndex(x, y, sX, sY);
    Vec3f& shadowVec = shadowMap->at<Vec3f>(sY, sX);
    double maxSum = 0;
    for (int i = 0; i < numOfClusters; i++) {
        double muSum = 0;
        for (int k = 0; k < channels; k++) {
            muSum += clusterMu.at<Vec3f>(i)[k];
        }
        if (muSum > maxSum) {
            maxSum = muSum;
            for (int k = 0; k < channels; k++) {
                shadowVec[k] = clusterMu.at<Vec3f>(i)[k];
            }
        }
    }

}

void FindReferenceIndex(int& refIndex, Mat& dsImage, Vec3f& ref) {

    // Set up expectation maximization model
    Ptr<EM> emModel = EM::create();
    emModel->setClustersNumber(numOfClustersRef);
    emModel->setCovarianceMatrixType(EM::COV_MAT_DIAGONAL);
    emModel->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, maxIters, emEps));

    // Cluster block with k means initializer
    Mat samples;

#if USE_SAMPLING

    Mat tmp(numOfGlobalSamples, 1, CV_32FC3, CV_RGB(-1, -1, -1));
    int* randInd = new int[numOfGlobalSamples];
    int size = width * height; // TODO: Use size_t
    vector<int> freeIndexes;
    for (int i = 0; i < size; i++) {
        freeIndexes.push_back(i);
    }
    int count = 0;
    int maxIndexCandidiate = -1;
    int delta = size / numOfGlobalSamples;
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(0, size);
    while (count < numOfGlobalSamples) {
        int indexCandidate = distribution(generator);
        vector<int>::iterator it = std::find(freeIndexes.begin(), freeIndexes.end(), indexCandidate);
        if (it != freeIndexes.end()) {
            randInd[count] = indexCandidate;
            freeIndexes.erase(it);
            count++;
        }
    }
    for (int i = 0; i < numOfGlobalSamples; i++) {
        tmp.at<Vec3f>(i) = image->at<Vec3f>(randInd[i]);
    }
    delete[] randInd;
    samples = tmp.reshape(1);

#else

    samples = dsImage.reshape(0, width * height);
        samples = samples.reshape(1);

#endif

    emModel->trainEM(samples);

    // Get the cluster means
    Mat clusterMu = emModel->getMeans();
    clusterMu = clusterMu.reshape(channels);
    clusterMu.convertTo(clusterMu, CV_32FC3);

    // Get cluster variances
    int maxInd = -1;
    double curMax = -1;
    for (int i = 0; i < numOfClustersRef; i++) {
        double muMag = 0;
        for (int k = 0; k < channels; k++) {
            muMag += clusterMu.at<Vec3f>(i)[k];
        }
        if (muMag > curMax) {
            curMax = muMag;
            maxInd = i;
        }
    }

    assert(maxInd != -1 && maxInd < numOfClustersRef);

    // Find the closest actual value to the cluster to choose as reference
    // TODO: stop earlier once threshold is met?
    ref = clusterMu.at<Vec3f>(maxInd);
    float curMin = std::numeric_limits<float>::max();
    refIndex = -1;
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            Vec3f curVal = dsImage.at<Vec3f>(i, j);
            float curMag = 0;
            for (int k = 0; k < channels; k++) {
                float diff = curVal[k] - ref[k];
                curMag += diff * diff;
            }
            if (curMag < curMin) {
                curMin = curMag;
                refIndex = j + i * width;
            }
        }
    }

}

void UpsampleShadowMap() {

    resize(*shadowMap, *shadowMap, Size(width, height), 0, 0, INTER_LANCZOS4);

}

void NormalizeShadowMap(int refIndex, Vec3f& ref) {

    assert(shadowMap->rows == height && shadowMap->cols == width);
    assert(refIndex >= 0 && refIndex < width * height);

    ref = shadowMap->at<Vec3f>(refIndex);

    // Divide each local paper intensity by the global reference
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            Vec3f& curShadowVec = shadowMap->at<Vec3f>(i, j);
            for (int k = 0; k < channels; k++) {

                curShadowVec[k] /= ref[k];

                // Clamp negative and zero values to a small number
                if (curShadowVec[k] <= 0) {
                    curShadowVec[k] = 1.0e-6f;
                }
            }
        }
    }

}

void ApplyShadowMap() {

    // Loop through all the pixels and divide by inverse gain
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            Vec3f invGain = shadowMap->at<Vec3f>(i, j);
            Vec3f& color = image->at<Vec3f>(i, j);
            for (int k = 0; k < channels; k++) {
                color[k] /= invGain[k];
            }
        }
    }

}

void ConvertIndex(int x, int y, int& xHat, int& yHat) {

    // Convert from original resolution to downsampled size (downsampled based on stride)
    xHat = (int)floor((x - 1) / float(stride)) + 1;
    yHat = (int)floor((y - 1) / float(stride)) + 1;

}

当我单击按钮处理图像时,应用程序将强制关闭,Logcat将显示如下

Logcat

我还在java和ndk中设置了我的opencv 这是Removing Shadow in doucment images

的原始代码

0 个答案:

没有答案