二値化について

333 views
Skip to first unread message

柴田怜央奈

unread,
Dec 19, 2013, 7:43:57 PM12/19/13
to android-g...@googlegroups.com
初めまして。ただいま卒業制作中のプログラム初心者の学生です。

OpenCVを使用した二値化を行いたいのですが、pathの取得がうまくできずnullポインタの例外のエラーが出てしまいます。このPath取得方法ではいけないのでしょうか?

DDMSのフォルダでは
mnt
shell
emulated
0
OpenCV
Sample
esukareta.jpg
となっております。

Androidバージョン4.3
Nexus7(2013)を使用しています。



package com.example.graduate_study;

import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;

//Binarization Page 選択写真の2値化
public class BinarizationActivity extends Activity{

private ImageView imgView;
@Override
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

     // cv::Mat gray_img = cv::imread("../../image/lenna.png", 1);
        String str = Environment.getExternalStorageDirectory().getPath()+"/OpenCV/Sample/esukareta.jpg";
        
        Mat srcMat = Highgui.imread(str, 1);
        
        if (!srcMat.empty()) {
        // グレースケール画像に変換
        Mat grayMat = new Mat();
        Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY);
        // 固定の閾値処理
    // cv::Mat bin_img, bininv_img, trunc_img, tozero_img, tozeroinv_img;
    Mat binMat = new Mat();
    
    // 入力画像, 出力画像, 閾値, maxVal, 閾値処理手法
    // cv::threshold(gray_img, bin_img, 0, 255, cv::THRESH_BINARY|cv::THRESH_OTSU); 
    Imgproc.threshold(grayMat, binMat, 0, 255, Imgproc.THRESH_BINARY|Imgproc.THRESH_OTSU);
    //適応的な閾値処理
    Mat adaptiveMat = new Mat();
    // 入力画像, 出力画像, maxVal, 閾値決定手法, 閾値処理手法, blockSize, C
    // cv::adaptiveThreshold(gray_img, adaptive_img, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 7, 8);
    Imgproc.adaptiveThreshold(grayMat, adaptiveMat, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 7, 8);
    Bitmap binImg = convMatToBitmap(binMat);
    ImageView binView = (ImageView)findViewById(R.id.ImageView);
    binView.setImageBitmap(binImg);
        }
}



    
// MatからBitmapに変換
Bitmap convMatToBitmap(Mat src) {
Mat dst = new Mat();
// GRAY→RGBAに変換
Imgproc.cvtColor(src, dst, Imgproc.COLOR_GRAY2RGBA, 4);
Bitmap img = Bitmap.createBitmap(src.width(), src.height(), Bitmap.Config.ARGB_8888);
// MatからBitmapに変換
Utils.matToBitmap(dst, img);
 
imgView.setImageBitmap(img);
return img;
}
 
}


よろしくお願いいたします。

長田努

unread,
Dec 19, 2013, 11:56:49 PM12/19/13
to android-g...@googlegroups.com
柴田さん、はじめまして。こんにち長田と申します。

OpenCVは利用した事が無かったのですが、少し試してみました。
既に解決済みでしたらスルーしてください。

柴田さんの作成法ですと、OpenCVのロードが完了する前にHighgui.imread()が呼ばれてしまっている為に、参照が出来ずに落ちている様ですね。

解決法としては以下URLになります。(中国語サイトで失礼)


要約すると、BaseLoaderCallbackを利用してロードの完了を待つ処理を入れるということです。

onCreate()にある『String str = Environment.getExternalStorageDirectory().』以降をメソッド化しておき、
代わりにonCreate()でOpenCvLoader.initAsync()を実行して、完了を非同期で待ちます。
完了後のコールバックでメソッド化した処理を呼び出せばHighgui.imread()で落ちなくなり正常動作すると思われます。

また、「getPath()+」以降のパスは本当にそこにファイルがあるかも確認してください。

、『private ImageView imgView;』、『imgView.setImageBitmap(img);』は要らなそうですね。

動作する完成コードを貼り付けたい所ですが、学生の本分を奪ってしまう事になるのでヒントのみにさせて頂きます。

※環境は柴田さんと同じNexus7(2013)のAndroid4.3で行いました。

参考になるか分かりませんが、お力になれていたら幸いです。
卒業制作ファイトです☆

長田


2013年12月20日 9:43 柴田怜央奈 <reon...@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループから退会し、メールの受信を停止するには、android-group-j...@googlegroups.com にメールを送信します。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては、https://groups.google.com/groups/opt_out にアクセスしてください。

柴田怜央奈

unread,
Dec 20, 2013, 2:49:45 AM12/20/13
to android-g...@googlegroups.com
長田さま

お早いお返事ありがとうございます。
行き詰っていたので長田さまのアドバイス非常に嬉しかったです。
長田さまのアドバイス通りおこなったところ、エラーが消えました!!!
本当にありがとうございます♪

しかし、TOP画面からボタン押下で二値化をする予定なのですが、
設定されているTOP画面がもう一度でてきてしまいます...

デバックをしたところ、このアクティビティを通ってない模様です。
いろいろ検証していますが、このような現象は長田さまのプログラムでは起きていないでしょうか?
大変失礼なのは承知ですがよろしくお願いいたします。


2013年12月20日金曜日 13時56分49秒 UTC+9 TOsada:
このグループから退会し、メールの受信を停止するには、android-group-japan+unsubscribe@googlegroups.com にメールを送信します。
このグループに投稿するには、android-group-ja...@googlegroups.com にメールを送信してください。

長田努

unread,
Dec 20, 2013, 3:43:13 AM12/20/13
to android-g...@googlegroups.com
柴田さん

お疲れ様です。長田です。
先ずは、エラーが消えたとの事で良かったです☆

今回、最初の投稿ソース以外は存じておらず、layoutを含め、柴田さんの記述内容がどの様な構造になっているか分かりませんが、長田が試したのは、提示なさっていたソースでonCreate()の内容をメソッド化し、BaseLoaderCallbackを追記して、オーバーライドしたonManagerConnected()にてSUCCESSを検知した後に処理を呼び出しただけですので、アプリ起動すると自動的にロードして二値化したBitmapがImageViewにセットされる動作をしています。
従って、TOP画面というものが存在しない為に、柴田さんの経験なさってる現象は確認できておきておりません。

可能であればソース(layoutも含む)を提示して頂いた方が問題ヶ所が特定し易いかと思われます。
申し訳ございませんが、全体の構造が把握できないので、Activityを通過していないというのがどの様な状態かはイメージできておりません。

ボタンを押すことで動作する様にするには、onManagerConnected()にてSUCCESSを検知した後にボタンを有効にするなど処理になるかと思います。
OpenCVのロードが完了したら、何らかのフラグを立てておいて利用可能を示し、ボタンが押された時にフラグを判定しロードするメソッドを実行する。
っと言ったフローになるかと思われますが…。


因みに、最初の投稿のソースから長田が変更したのは以下になります。

■BinarizationActivityのonCreate()に記述されていた最初のコメントから全文をloadImage()というメソッドに移行。

BinarizationActivityに以下の匿名関数によるコールバック変数を記述

private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS: {
Log.i("test", "OpenCV loaded successfully");
// Create and set View
loadImage();
}
break;
default: {
super.onManagerConnected(status);
}
break;
}
}
};

※基本的にお伝えしたURLの対処法の丸コピです。

このコールバック内のswitchにあるSUCCESSでloadImage()が呼ばれる事で画像をロードして二値化しています。
ボタンをトリガーにする場合、loadImage()の代わりに参照できるスコープの変数にフラグを持ち、ボタンが押されて処理する際に続行して良い(OpenCVロード済み)かを判断する。
そして、続行可能だった際にloadImage()を呼び出せば希望に近しき動作をするかと思います。


この提示だけでは、色々と問題点も残ってしまいますが、新たに出てくる問題点は柴田さんが後々に精査していただくとして、大凡の動きはそんな感じになっていくのかなと考えています。
イマイチ掴めない様でしたら、ソースの提示をして頂ければと存じます。

宜しくお願い致します。

長田



2013年12月20日 16:49 柴田怜央奈 <reon...@gmail.com>:
長田さま

お早いお返事ありがとうございます。
行き詰っていたので長田さまのアドバイス非常に嬉しかったです。
長田さまのアドバイス通りおこなったところ、エラーが消えました!!!
本当にありがとうございます♪

しかし、TOP画面からボタン押下で二値化をする予定なのですが、
設定されているTOP画面がもう一度でてきてしまいます...

デバックをしたところ、このアクティビティを通ってない模様です。
いろいろ検証していますが、このような現象は長田さまのプログラムでは起きていないでしょうか?
大変失礼なのは承知ですがよろしくお願いいたします。


2013年12月20日金曜日 13時56分49秒 UTC+9 TOsada:
柴田さん、はじめまして。こんにち長田と申します。

OpenCVは利用した事が無かったのですが、少し試してみました。
既に解決済みでしたらスルーしてください。

柴田さんの作成法ですと、OpenCVのロードが完了する前にHighgui.imread()が呼ばれてしまっている為に、参照が出来ずに落ちている様ですね。

解決法としては以下URLになります。(中国語サイトで失礼)

このグループから退会し、メールの受信を停止するには、android-group-j...@googlegroups.com にメールを送信します。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
Reply all
Reply to author
Forward
0 new messages