From 90b96eca6b2dd33cfec14ae3f40c0d2fa806ddfd Mon Sep 17 00:00:00 2001 From: OziinG Date: Sat, 7 Dec 2024 11:23:29 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20payload=20=EC=88=98=EC=A0=95=20(#261?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mhnfe/domain/ai/BoundingBoxUtils.kt | 73 ++++++------------- .../mhnfe/domain/mqtt/MqttViewModel.kt | 33 ++++++--- .../ui/screens/monitoring/kvs/AiViewModel.kt | 16 ++-- .../ui/screens/monitoring/kvs/WebRTCScreen.kt | 8 +- 4 files changed, 60 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt b/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt index b6043dc2..03d11521 100644 --- a/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt +++ b/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt @@ -1,61 +1,36 @@ package com.example.mhnfe.domain.ai import com.example.mhnfe.domain.ai.yolo.BoundingBox -import org.json.JSONObject - -// 좌표 데이터 클래스 -data class BoundingBoxCoordinates( - val x1: Int, val y1: Int, - val x2: Int, val y2: Int, - val x3: Int, val y3: Int, - val x4: Int, val y4: Int -) object BoundingBoxUtils { - // BoundingBox 객체의 좌표를 BoundingBoxCoordinates 객체로 변환 - private fun boundingBoxCoordinates(box: BoundingBox): BoundingBoxCoordinates { - return BoundingBoxCoordinates( - x1 = box.x1.toInt(), // 좌상단 x - y1 = box.y1.toInt(), // 좌상단 y - x2 = box.x2.toInt(), // 우상단 x - y2 = box.y1.toInt(), // 우상단 y (같은 y값) - x3 = box.x1.toInt(), // 좌하단 x (같은 x값) - y3 = box.y2.toInt(), // 좌하단 y - x4 = box.x2.toInt(), // 우하단 x (같은 x값) - y4 = box.y2.toInt() // 우하단 y - ) - } - - // 각 박스의 좌표를 JSON 형식으로 반환 - fun generateCoordinatesJson(boundingBoxes: List): String { - return JSONObject().apply { - boundingBoxes.forEachIndexed { index, box -> - val coordinates = boundingBoxCoordinates(box) - put("box_$index", JSONObject().apply { - put("x1", coordinates.x1) - put("y1", coordinates.y1) - put("x2", coordinates.x2) - put("y2", coordinates.y2) - put("x3", coordinates.x3) - put("y3", coordinates.y3) - put("x4", coordinates.x4) - put("y4", coordinates.y4) - }) - } - }.toString() - } - - fun generateObjectNameJson(boundingBoxes: List): String = - boundingBoxes.joinToString(prefix = "[", postfix = "]") { box -> - "{\"object_name\":\"${box.objectName}\"}" + // 객체 이름과 신뢰도를 각각 반환하는 메서드 + fun getTypeAndConfidence(boundingBoxes: List): Pair { + return if (boundingBoxes.isNotEmpty()) { + val box = boundingBoxes.first() + box.objectName to box.cnf + } else { + "unknown" to 0.0f } + } - fun generateConfidenceJson(boundingBoxes: List): String = - boundingBoxes.joinToString(prefix = "[", postfix = "]") { box -> - "{\"confidence\":${box.cnf}}" + // 각 박스의 좌표를 반환하는 메서드 + fun getCoordinates(boundingBoxes: List): List> { + return boundingBoxes.map { box -> + mapOf( + "x1" to box.x1, + "y1" to box.y1, + "x2" to box.x2, + "y2" to box.y1, + "x3" to box.x1, + "y3" to box.y2, + "x4" to box.x2, + "y4" to box.y2 + ) } + } + // 이벤트 발생 여부를 결정하는 메서드 fun shouldTriggerEvent(lastEventTime: Long, eventDelayMillis: Long): Boolean = (System.currentTimeMillis() - lastEventTime) >= eventDelayMillis -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt b/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt index 81f6f116..10ba4e23 100644 --- a/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt +++ b/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt @@ -307,19 +307,30 @@ class MqttViewModel @Inject constructor( fun eventTopic( trackingId: Int, objectName: String, - coordinates: String, - confidence: String + confidence: Float, + coordinates: List> ) { + val coordinatesJson = coordinates.firstOrNull()?.let { coord -> + """ + { + "x1": ${coord["x1"]}, "y1": ${coord["y1"]}, + "x2": ${coord["x2"]}, "y2": ${coord["y2"]}, + "x3": ${coord["x3"]}, "y3": ${coord["y3"]}, + "x4": ${coord["x4"]}, "y4": ${coord["y4"]} + } + """.trimIndent() + } ?: "{}" + val payload = """ - { - "trackingId": $trackingId, - "timestamp": ${System.currentTimeMillis() / 1000}, - "objectType": "$objectName", - "confidence": "$confidence", - "coordinates": $coordinates - } - """.trimIndent() + { + "trackingId": $trackingId, + "timestamp": ${System.currentTimeMillis() / 1000}, + "objectType": "$objectName", + "confidence": $confidence, + "coordinates": $coordinatesJson + } + """.trimIndent() publish("/mhn/event/detect/things/$thingId", payload) } @@ -343,7 +354,7 @@ class MqttViewModel @Inject constructor( private fun publish(topic: String, payload: String) { try { awsMqttManager.publishString(payload, topic, AWSIotMqttQos.QOS0) - Log.d(tag, "Published to topic $topic: $payload") + Log.d(tag, "Published to topic $topic: \n $payload") } catch (e: Exception) { Log.e(tag, "Failed to publish message: ${e.message}", e) } diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt index e3797dfa..4a209624 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt @@ -27,7 +27,10 @@ class AiViewModel @Inject constructor( private var lastEventTime: Long = 0 // 마지막 이벤트 발생 시간 기록 private val eventDelayMillis = 500L // event data to iot 딜레이 시간 - fun processFrame(bitmap: Bitmap?, onResult: (Int, String, String, String) -> Unit) { + fun processFrame( + bitmap: Bitmap?, + onResult: (Int, String, Float, List>) -> Unit + ) { viewModelScope.launch { try { bitmap?.let { bmp -> @@ -46,12 +49,13 @@ class AiViewModel @Inject constructor( val trackingId = DetectionManager.getNextTrackingId() - // BoundingBoxUtil을 사용하여 JSON 데이터 생성 - val coordinatesJson = BoundingBoxUtils.generateCoordinatesJson(boundingBoxes) - val objectNameJson = BoundingBoxUtils.generateObjectNameJson(boundingBoxes) - val confidenceJson = BoundingBoxUtils.generateConfidenceJson(boundingBoxes) + // BoundingBoxUtils를 사용하여 데이터 추출 + val (objectType, confidence) = BoundingBoxUtils.getTypeAndConfidence( + boundingBoxes + ) + val coordinates = BoundingBoxUtils.getCoordinates(boundingBoxes) - onResult(trackingId, coordinatesJson, objectNameJson, confidenceJson) + onResult(trackingId, objectType, confidence, coordinates) } } } diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/WebRTCScreen.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/WebRTCScreen.kt index 9a6d02cf..2969d6b0 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/WebRTCScreen.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/WebRTCScreen.kt @@ -277,12 +277,12 @@ fun WebRtcScreen( if (!isCameraSwitching) { bitmap?.let { withContext(Dispatchers.Default) { - aiViewModel.processFrame(it) { trackingId, coordinatesJson, objectName, confidence -> + aiViewModel.processFrame(it) { trackingId, objectType, confidence, coordinates -> mqttViewModel.eventTopic( trackingId, - objectName, - coordinatesJson, - confidence + objectType, + confidence, + coordinates ) } } From 9195dac30fed686d35a3501804cac507fd0f6903 Mon Sep 17 00:00:00 2001 From: OziinG Date: Sat, 7 Dec 2024 12:59:10 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=201280=20*=20720=20=EC=9C=84=EC=B9=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=ED=99=98=20(#261)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mhnfe/domain/ai/BoundingBoxUtils.kt | 20 +++++++-- .../domain/ai/yolo/BoundingBoxProcessor.kt | 44 ++++++++++--------- .../mhnfe/domain/mqtt/MqttViewModel.kt | 32 ++++++-------- .../ui/screens/monitoring/kvs/AiViewModel.kt | 2 +- 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt b/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt index 03d11521..5da96521 100644 --- a/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt +++ b/app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt @@ -15,17 +15,17 @@ object BoundingBoxUtils { } // 각 박스의 좌표를 반환하는 메서드 - fun getCoordinates(boundingBoxes: List): List> { + fun getCoordinates(boundingBoxes: List): List> { return boundingBoxes.map { box -> mapOf( "x1" to box.x1, "y1" to box.y1, "x2" to box.x2, - "y2" to box.y1, + "y2" to box.y2, "x3" to box.x1, "y3" to box.y2, "x4" to box.x2, - "y4" to box.y2 + "y4" to box.y1 ) } } @@ -33,4 +33,18 @@ object BoundingBoxUtils { // 이벤트 발생 여부를 결정하는 메서드 fun shouldTriggerEvent(lastEventTime: Long, eventDelayMillis: Long): Boolean = (System.currentTimeMillis() - lastEventTime) >= eventDelayMillis + + // 좌표를 단일 JSON 객체로 변환하는 메서드 + fun getFirstCoordinatesAsJson(boundingBoxes: List): String { + return boundingBoxes.firstOrNull()?.let { box -> + """ + { + "x1": ${box.x1}, "y1": ${box.y1}, + "x2": ${box.x2}, "y2": ${box.y2}, + "x3": ${box.x1}, "y3": ${box.y2}, + "x4": ${box.x2}, "y4": ${box.y1} + } + """.trimIndent() + } ?: "{}" + } } diff --git a/app/src/main/java/com/example/mhnfe/domain/ai/yolo/BoundingBoxProcessor.kt b/app/src/main/java/com/example/mhnfe/domain/ai/yolo/BoundingBoxProcessor.kt index e697d903..875d9369 100644 --- a/app/src/main/java/com/example/mhnfe/domain/ai/yolo/BoundingBoxProcessor.kt +++ b/app/src/main/java/com/example/mhnfe/domain/ai/yolo/BoundingBoxProcessor.kt @@ -1,12 +1,12 @@ package com.example.mhnfe.domain.ai.yolo data class BoundingBox( - val x1: Float, - val y1: Float, - val x2: Float, - val y2: Float, - val w: Float, // 너비 - val h: Float, // 높이 + val x1: Int, + val y1: Int, + val x2: Int, + val y2: Int, + val w: Int, // 너비 + val h: Int, // 높이 val cnf: Float, // confidence val idxNum: Int, // 탐지된 번호 val objectName: String @@ -18,6 +18,8 @@ object BoundingBoxProcessor { private const val CONFIDENCE_THRESHOLD = 0.3F private const val IOU_THRESHOLD = 0.5F private const val TAG = "BoundingBoxProcessor" + private const val SCREEN_WIDTH = 1280 + private const val SCREEN_HEIGHT = 720 // 콜백 -> 탐지된 객체 정보를 처리하도록 수정 fun bestBoxes( @@ -45,23 +47,23 @@ object BoundingBoxProcessor { if (maxConf > CONFIDENCE_THRESHOLD) { val clsName = labels[maxIdx] - val cx = array[c] - val cy = array[c + numElements] - val w = array[c + numElements * 2] - val h = array[c + numElements * 3] - val x1 = cx - (w / 2F) - val y1 = cy - (h / 2F) - val x2 = cx + (w / 2F) - val y2 = cy + (h / 2F) - if (x1 < 0F || x1 > 1F) continue - if (y1 < 0F || y1 > 1F) continue - if (x2 < 0F || x2 > 1F) continue - if (y2 < 0F || y2 > 1F) continue + val cx = array[c] * SCREEN_WIDTH + val cy = array[c + numElements] * SCREEN_HEIGHT + val w = array[c + numElements * 2] * SCREEN_WIDTH + val h = array[c + numElements * 3] * SCREEN_HEIGHT + val x1 = (cx - (w / 2F)).toInt() + val y1 = (cy - (h / 2F)).toInt() + val x2 = (cx + (w / 2F)).toInt() + val y2 = (cy + (h / 2F)).toInt() + if (x1 < 0 || x1 > SCREEN_WIDTH) continue + if (y1 < 0 || y1 > SCREEN_HEIGHT) continue + if (x2 < 0 || x2 > SCREEN_WIDTH) continue + if (y2 < 0 || y2 > SCREEN_HEIGHT) continue boundingBoxes.add( BoundingBox( x1 = x1, y1 = y1, x2 = x2, y2 = y2, - w = w, h = h, + w = w.toInt(), h = h.toInt(), cnf = maxConf, idxNum = maxIdx, objectName = clsName ) ) @@ -106,9 +108,9 @@ object BoundingBoxProcessor { val y1 = maxOf(box1.y1, box2.y1) val x2 = minOf(box1.x2, box2.x2) val y2 = minOf(box1.y2, box2.y2) - val intersectionArea = maxOf(0F, x2 - x1) * maxOf(0F, y2 - y1) + val intersectionArea = maxOf(0F, (x2 - x1).toFloat()) * maxOf(0F, (y2 - y1).toFloat()) val box1Area = box1.w * box1.h val box2Area = box2.w * box2.h return intersectionArea / (box1Area + box2Area - intersectionArea) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt b/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt index 10ba4e23..e8630c12 100644 --- a/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt +++ b/app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt @@ -308,33 +308,29 @@ class MqttViewModel @Inject constructor( trackingId: Int, objectName: String, confidence: Float, - coordinates: List> + coordinates: List> ) { - val coordinatesJson = coordinates.firstOrNull()?.let { coord -> + val payload = coordinates.firstOrNull().let { coord -> """ { - "x1": ${coord["x1"]}, "y1": ${coord["y1"]}, - "x2": ${coord["x2"]}, "y2": ${coord["y2"]}, - "x3": ${coord["x3"]}, "y3": ${coord["y3"]}, - "x4": ${coord["x4"]}, "y4": ${coord["y4"]} + "trackingId": $trackingId, + "timestamp": ${System.currentTimeMillis() / 1000}, + "objectType": "$objectName", + "confidence": $confidence, + "coordinates": { + "x1": ${coord!!["x1"]}, "y1": ${coord["y1"]}, + "x2": ${coord["x2"]}, "y2": ${coord["y2"]}, + "x3": ${coord["x3"]}, "y3": ${coord["y3"]}, + "x4": ${coord["x4"]}, "y4": ${coord["y4"]} + } } """.trimIndent() - } ?: "{}" - - val payload = - """ - { - "trackingId": $trackingId, - "timestamp": ${System.currentTimeMillis() / 1000}, - "objectType": "$objectName", - "confidence": $confidence, - "coordinates": $coordinatesJson - } - """.trimIndent() + } publish("/mhn/event/detect/things/$thingId", payload) } + //shadow fun subscribeShadowWithPayload(thingId: String, data: (ReportedData?) -> Unit) { val topic = "\$aws/things/${thingId}/shadow/update/accepted" diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt index 4a209624..cd5623f9 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt @@ -29,7 +29,7 @@ class AiViewModel @Inject constructor( fun processFrame( bitmap: Bitmap?, - onResult: (Int, String, Float, List>) -> Unit + onResult: (Int, String, Float, List>) -> Unit ) { viewModelScope.launch { try { From ea1211650a84f509504e1957d6c4fe12868d9c8b Mon Sep 17 00:00:00 2001 From: OziinG Date: Sat, 7 Dec 2024 16:27:10 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20AI=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B0=84=EA=B2=A9=201=EB=B6=84=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20(#261)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt index 4d7bcec3..abbf28b9 100644 --- a/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt +++ b/app/src/main/java/com/example/mhnfe/ui/screens/monitoring/kvs/AiViewModel.kt @@ -33,7 +33,7 @@ class AiViewModel @Inject constructor( private val motionDetector = MotionDetector() private val yoloDetectionManager = YoloDetectionManager(context) private var lastEventTime: Long = 0 // 마지막 이벤트 발생 시간 기록 - private val eventDelayMillis = 500L // event data to iot 딜레이 시간 + private val eventDelayMillis = 6000L // event data to iot 딜레이 시간 private val handleDetection = HandleDetection() fun processFrame(