안녕하세요.
android opencv library를 사용하여 image를 crop하고 있습니다.
어떤 디바이스에서는 이런 이슈가 나오는데 이 이슈에 대한 정보를 아시는 분은
이슈에 대한 정보와 해결책을 알려주시면 감사하겠습니다.
아래는 해당 소스입니다.
File fileFolio = new File(bmpFilePath);
String filePath = fileFolio.getParent();
/**원본 Bitmap 이미지 흑백 이미지로 불러오기*/
Log.d(TAG, "deskew crop scannedBmpFilePath: " + bmpFilePath);
Mat matOriginal = Imgcodecs.imread(bmpFilePath, Imgcodecs.IMREAD_GRAYSCALE);
Log.d(TAG, "deskew crop imread complete");
/**흑백 Bitmap 이미지를 Png 이미지로 저장*/
Log.d(TAG, "deskew crop show image");
matResult = matOriginal.clone();
matOriginal.release();
// crop 기능 시작
Log.d(TAG, "Image Crop start");
File pngOriginal = new File(filePath, fileFolio.getName() + "_grayscaled.png");
pngResult = pngOriginal.getAbsolutePath();
matRgb = new Mat();
Imgproc.cvtColor(matOriginal, matRgb, Imgproc.COLOR_GRAY2RGB);
Imgcodecs.imwrite(pngResult, matRgb);
matRgb.release();
/*Crop 영역 얻어오기*/
int[] aryRectContent = HelperImageProcess.findCropBoundary(matResult.getNativeObjAddr());
int x = aryRectContent[0];
int y = aryRectContent[1];
int width = aryRectContent[2];
int height = aryRectContent[3];
Rect roi = new Rect(x, y, width, height);
HelperImageProcess.findCropBoundary(matResult.getNativeObjAddr());
위 코드에서 이슈가 나는 것 같습니다.
아래는 위 코드의 소스입니다.
Mat &matInput = *(Mat *) matAddrInput; // OpenCV에서 사용하는 이미지 객체 (grayscale로 변환 된 이미지일 것)
LOGD(LOG_TAG, "matInput channels: %d", matInput.channels());
LOGD(LOG_TAG, "matInput channels: %d", matInput.rows);
LOGD(LOG_TAG, "matInput channels: %d", matInput.cols);
int i, x, y, z; // Loop 인덱스
int iCutThreshold = 80; // 바탕에 밝은 영역이 많을 수록 값을 증가 시키도록 한다. 실제 이미지를 통해 조절하도록!
bool bFlag; // 중첩 Loop 탈출 플래그
int Offset = 2; // 상하좌우 순회 시작 위치를 약간 띄고 시작. 노이즈로 인해 최외곽 영역에 흰 줄이 가는 경우 대비.
int iBundle = 10;
int iCount;
// 이미지 최대 외곽 영역에서 최소 영역으로 점차 좁혀갈 최종 영역
int rcCrop_top = 0;
int rcCrop_bottom = matInput.rows - 1;
int rcCrop_left = 0;
int rcCrop_right = matInput.cols;
// FIXME: 만일 skew 가 반시계 방향이었다면 좌측 상단은 잘려있을 수 있으므로, deskew 후에 안잘린 우측에서 좌측으로 순회하자. 같은 이유로 상하좌우 4 방향으로 영역 좁힐 때 모두가 마찬가지.
// TODO: Crop 이후에 잘려있던 검은 영역을 흰색으로 채워줄 지는 논의 필요.
// top
bFlag = false;
for (y = Offset; y < matInput.rows - Offset; y++) {
for (x = Offset; x < matInput.cols - Offset; x += 4) {
if (matInput.at<uchar>(y, x) > iCutThreshold) {
iCount = 0;
for (z = 0; z < iBundle; z++) {
if (matInput.at<uchar>(y + z, x + z) > iCutThreshold) iCount++;
}
if (iCount == iBundle) {
rcCrop_top = y;
bFlag = true;
break;
}
}
}
if (bFlag) break;
}
// bottom
bFlag = false;
for (y = matInput.rows - 1 - Offset; y >= Offset; y--) {
for (x = Offset; x < matInput.cols - Offset; x += 4) {
if (matInput.at<uchar>(y, x) > iCutThreshold) {
iCount = 0;
for (z = 0; z < iBundle; z++) {
if (matInput.at<uchar>(y - z, x + z) > iCutThreshold) iCount++;
}
if (iCount == iBundle) {
rcCrop_bottom = y;
bFlag = true;
break;
}
}
}
if (bFlag) break;
}
// left
bFlag = false;
for (x = Offset; x < matInput.cols - Offset; x++) {
for (y = Offset; y < matInput.rows - Offset; y += 4) {
if (matInput.at<uchar>(y, x) > iCutThreshold) {
iCount = 0;
for (z = 0; z < iBundle; z++) {
if (matInput.at<uchar>(y + z, x + z) > iCutThreshold) iCount++;
}
if (iCount == iBundle) {
rcCrop_left = x;
bFlag = true;
break;
}
}
}
if (bFlag) break;
}
// right
bFlag = false;
for (x = matInput.cols - 1 - Offset; x >= Offset; x--) {
for (y = Offset; y < matInput.rows - Offset; y += 4) {
if (matInput.at<uchar>(y, x) > iCutThreshold) {
iCount = 0;
for (z = 0; z < iBundle; z++) {
if (matInput.at<uchar>(y - z, x - z) > iCutThreshold) iCount++;
}
if (iCount == iBundle) {
rcCrop_right = x;
bFlag = true;
break;
}
}
}
if (bFlag) break;
}
// C++ opencv CvRect 와 Java opencv Rect 쌍을 맞추어 반환
CvRect rect(rcCrop_left, rcCrop_top, rcCrop_right - rcCrop_left, rcCrop_bottom - rcCrop_top);
// 상하좌우 픽셀 인덱스를 보관할 자바 정수형 배열 생성
jintArray intArray = env->NewIntArray(4);
// C 배열 포인터를 이용하여 자바 정수형 배열을 설정 (순서 주의! Java 코드와 맞추어야 함. x, y, width, height)
jint *ptrArray = env->GetIntArrayElements(intArray, nullptr);
ptrArray[0] = rect.x;
ptrArray[1] = rect.y;
ptrArray[2] = rect.width;
ptrArray[3] = rect.height;
// C 배열 포인터 해제
env->ReleaseIntArrayElements(intArray, ptrArray, 0);
// 자바 정수형 배열 반환
return intArray;
아래는 해당 로그입니다.
08-31 18:02:31.977 1889-2045/kr.co.mirusystems.rts A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x9b3ffffa in tid 2045 (AsyncTask #3)
08-31 18:02:32.032 124-124/? I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
08-31 18:02:32.032 124-124/? I/DEBUG: Build fingerprint: 'Android/aosp_s5p6818_drone/s5p6818_drone:5.1.1/LMY48G/root11101821:userdebug/test-keys'
08-31 18:02:32.032 124-124/? I/DEBUG: Revision: '0'
08-31 18:02:32.032 124-124/? I/DEBUG: ABI: 'arm'
08-31 18:02:32.033 124-124/? I/DEBUG: pid: 1889, tid: 2045, name: AsyncTask #3 >>> kr.co.mirusystems.rts <<<
08-31 18:02:32.033 124-124/? I/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x9b3ffffa
08-31 18:02:32.071 124-124/? I/DEBUG: r0 9b3ffffa r1 00000a1a r2 ffffffff r3 00000a1a
08-31 18:02:32.072 124-124/? I/DEBUG: r4 a2b2330c r5 af4b72e0 r6 89805f0c r7 a2b232e8
08-31 18:02:32.072 124-124/? I/DEBUG: r8 a2b23390 r9 b4b07400 sl a2b23310 fp b4b07400
08-31 18:02:32.072 124-124/? I/DEBUG: ip ffffffff sp a2b23230 lr af466078 pc a37ff458 cpsr 200f0030
08-31 18:02:32.072 124-124/? I/DEBUG: backtrace:
08-31 18:02:32.072 124-124/? I/DEBUG: #00 pc 00002458 /data/app/kr.co.mirusystems.rts-1/lib/arm/libdeskewcrop-lib.so (Java_kr_co_mirusystems_deskewcrop_helper_HelperImageProcess_findCropBoundary+839)
08-31 18:02:32.072 124-124/? I/DEBUG: #01 pc 000a2d81 /system/lib/libart.so (art_quick_generic_jni_trampoline+32)
08-31 18:02:32.072 124-124/? I/DEBUG: #02 pc 000a989c /dev/ashmem/dalvik-non moving space (deleted)
08-31 18:02:33.680 124-124/? I/DEBUG: Tombstone written to: /data/tombstones/tombstone_00