我正在处理我的项目,这是关于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将显示如下
我还在java和ndk中设置了我的opencv 这是Removing Shadow in doucment images
的原始代码