Android에서...
Kotlin
지금 android studio의 kotlin 활용 비율이 점점 증가한다고는 하지만,
opencv, ndk 등의 엔지니어링 예제를 본다면 아직 정보가 많이 부족한 것으로 보인다.
이에 따라 사소한 것이라도 조금씩 적는다면 누군가에게는 도움이 되지 않을까...!
NDK
ndk는 Android Studio 내에서 C++로 작업할 수 있게 도와준다.
이를 통해 기존 C 코드를 쉽게 옮길 수 도 있으며, OpenCL을 사용할 때 매우 유용하게 사용된다.
기본 설정
우선 NDK와 NDK 내 opencv 사용 설정은 아래 블로그를 참조하여 진행했다.
NDK 및 OpenCV 설정
Code
Asset 내 이미지를 비트맵으로 입력받아 Mat 형태로 FAST keypoint detection하는 어플을 만들고자 한다.
activity_main
Android으로 OpenCV 사용하기 - 2
우선 앞 내용의 activity_main 예제에 기존 이미지와 keypoint detection된 이미지를 출력하는 imageView를 추가했다.
<ImageView
android:id="@+id/sourceImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/targetImageView"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_weight="0.55" />
<ImageView
android:id="@+id/targetImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@id/sourceImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/sourceImageView"
app:layout_constraintTop_toTopOf="@id/sourceImageView" />
MainActivity
FAST detection function (NDK)
class MainActivity
MainActivity 클래스 내부에 external fun 함수를 추가한다.
난 해당 코드에서는 한 이미지만 으로 계산하므로 kotlin 내 이미지의 주솟값만을 입력으로 줄 것이다.
class MainActivity : AppCompatActivity() {
...
external fun getKeypointImages(inputImage: Long)
}
native-lib
getKeypointImages 함수를
Java_edu_android_project_home_1ndk_1opencv_MainActivity_getKeypointImages
의 함수로 native-lib.cpp에서 구현한다.
extern "C" JNIEXPORT void JNICALL
Java_edu_android_project_home_1ndk_1opencv_MainActivity_getKeypointImages(
JNIEnv* env,
jobject instance,
jlong inputImage) {
// input image의 주소를 통해 아래와 같이 설정
Mat &image_input = *(Mat *)inputImage;
// gray 이미지를 저장할 Mat 변수 선언
Mat image_buffer = image_input.clone();
// fast Detection을 위해 GRAY로 변경
cvtColor(image_input, image_buffer, COLOR_BGR2GRAY);
// keypoint detect
vector<KeyPoint> keypoints;
FAST(image_buffer, keypoints, 60, true);
// gray가 아닌 input 이미지에 바로 입력한다
drawKeypoints(image_input, keypoints, image_input, Scalar::all(-1), DrawMatchesFlags::DRAW_OVER_OUTIMG);
// buffer 이미지의 메모리를 해제한다
image_output.release();
}
kotlin에서는 public native 가 아닌, external fun 을 사용한다.
Java와는 다르게 "alt + enter"를 통한 native-lib에 함수 자동 생성이 불가하다.
private fun setImage(idx: Int)
private fun setImage(idx: Int) 함수를 통해 idx에 해당하는 Assets 폴더 내 이미지를
불러와 FAST keypoint detection을 진행한다.
해당 프로젝트에서는 left, right 버튼이 눌릴 때마다 함수를 불러오며 이미지 keypoint를 계산한다.
버튼 관련 내용은 아래 링크를 참조하길 바란다.
Android으로 OpenCV 사용하기 - 3
Asset 폴더 내 이미지 불러오기
left, right 버튼에 따른 이미지 변경이나 asset 이미지 불러오는 방식은 위 링크와 모두 동일하다.
class MainActivity : AppCompatActivity() {
...
private fun setImage(idx: Int) {
val inputStream: InputStream
val name: String = "img_" + String.format("%04d", idx) + ".png"
Log.d("MainActivity", "name : $name") // name 확인을 위한 출력
inputStream = assets.open(name) // name에 해당하는 파일 open
// 기존 이미지를 출력할 leftImageView 설정
srcBitmap = BitmapFactory.decodeStream(inputStream)
srcImageView.setImageBitmap(srcBitmap)
Utils.bitmapToMat(srcBitmap, image)
...
}
}
keypoint 이미지 불러오기
getKeypointImages 함수는 Mat의 주솟값을 받아오므로 image.nativeObjAddr 을 input으로 받는다.
class MainActivity : AppCompatActivity() {
...
private fun setImage(idx: Int) {
...
// getKeypointImage 함수 이후 이미지 크기 확인
Log.d(TAG, "width : ${image.cols()} height : ${image.rows()}")
getKeypointImages(image.nativeObjAddr)
Log.d(TAG, "width : ${resultImage.cols()} height : ${resultImage.rows()}")
val trgBitmap = Bitmap.createBitmap(
resultImage.cols(),
resultImage.rows(),
Bitmap.Config.RGB_565
)
Utils.matToBitmap(image, trgBitmap)
// view에 이미지를 설정한다.
trgImageView.setImageBitmap(trgBitmap)
// 현재 index 출력
indexTextView.text = "index : $idx"
}
}
Result
이번 프로젝트를 통해 FAST keypoint detection이 된 이미지를 출력할 수 있다.
전체 MainActivity
class MainActivity : AppCompatActivity() {
companion object {
private val TAG = MainActivity::class.simpleName
// Used to load the 'native-lib' library on application startup.
init {
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "OpenCV is not loaded!")
} else {
Log.d(TAG, "OpenCV is loaded successfully!")
}
System.loadLibrary("native-lib")
}
}
private val srcImageView: ImageView by lazy {
findViewById<ImageView>(R.id.sourceImageView)
}
private val trgImageView: ImageView by lazy {
findViewById<ImageView>(R.id.targetImageView)
}
private val indexTextView: TextView by lazy {
findViewById<TextView>(R.id.indexTextView)
}
private lateinit var srcBitmap: Bitmap
var image = Mat()
var resultImage = Mat()
var num: Int = 20
var index: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setImage(index)
}
@SuppressLint("SetTextI18n")
private fun setImage(idx: Int) {
val inputStream: InputStream
val name: String = "img/img_" + String.format("%04d", idx) + ".png"
Log.d("MainActivity", "name : $name") // name 확인을 위한 출력
inputStream = assets.open(name) // name에 해당하는 파일 open
srcBitmap = BitmapFactory.decodeStream(inputStream)
srcImageView.setImageBitmap(srcBitmap)
Utils.bitmapToMat(srcBitmap, image)
Log.d(TAG, "width : ${image.cols()} height : ${image.rows()}")
getKeypointImages(image.nativeObjAddr)
Log.d(TAG, "width : ${image.cols()} height : ${image.rows()}")
val trgBitmap = Bitmap.createBitmap(
image.cols(),
image.rows(),
Bitmap.Config.RGB_565
)
Utils.matToBitmap(image, trgBitmap)
// view에 이미지를 설정한다.
trgImageView.setImageBitmap(trgBitmap)
indexTextView.text = "index : $idx"
}
fun getLeftButton(view: View) {
index--
if(index < 0) {
Toast.makeText(this, "첫번째 이미지입니다.", Toast.LENGTH_SHORT).show()
index = 0
}
Log.d("MainActivity", "index : $index")
setImage(index)
}
fun getRightButton(view: View) {
index++
if(index >= num) {
Toast.makeText(this, "마지막 이미지입니다.", Toast.LENGTH_SHORT).show()
index = num - 1
}
Log.d("MainActivity", "index : $index")
setImage(index)
}
external fun getKeypointImages(inputImage: Long)
}
'IT > Android' 카테고리의 다른 글
[OpenGL ES] Android NDK 환경에서 glm 라이브러리 사용하기 (0) | 2021.09.01 |
---|---|
[Android] Android으로 OpenCV 사용하기 - 3 (0) | 2021.08.03 |
[Android] Android으로 OpenCV 사용하기 - 2 (0) | 2021.08.03 |
[Android] Android으로 OpenCV 사용하기 - 1 (0) | 2021.08.03 |