Skip to content

Commit

Permalink
Merge pull request #264 from IoTeaTime/fix/261-ai-json-format
Browse files Browse the repository at this point in the history
fix: ai 감지 이벤트의 json 형식 수정
  • Loading branch information
OziinG authored Dec 7, 2024
2 parents 79643c1 + ea12116 commit a85f2e6
Show file tree
Hide file tree
Showing 24 changed files with 192 additions and 163 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class AuthAuthenticator @Inject constructor(
return runBlocking {
// val newTokenResult = tokenManager.refreshAccessToken()
try {
Log.d("AuthAuthenticator","get newToken try")
Log.d("AuthAuthenticator", "get newToken try")
val newTokenResult = tokenManager.refreshAccessToken()
Log.d("AuthAuthenticator","AuthAuthenticator get newToken!!}")
Log.d("AuthAuthenticator", "AuthAuthenticator get newToken!!}")
if (newTokenResult != null) {
val accessToken = newTokenResult
// Update the access token in your storage.
Expand All @@ -46,7 +46,10 @@ class AuthAuthenticator @Inject constructor(
.header("Authorization", accessToken)
.build()
} else {
Log.d("AuthAuthenticator","AuthAuthenticator failed by expired refreshToken!!")
Log.d(
"AuthAuthenticator",
"AuthAuthenticator failed by expired refreshToken!!"
)
return@runBlocking null
}
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ interface ImageApi {
@Url presignedUrl: String,
@Body image: RequestBody
): Response<Unit>

@POST("api/image-device")
suspend fun imageDevice(
@Header("Authorization") token: String,
@Body request: ImageSaveRequest
) : saveImageResponse
): saveImageResponse

@POST("/api/image-device/presigned-url")
suspend fun urlImage(
suspend fun urlImage(
@Header("Authorization") token: String,
@Body request: ImageRequest
) : ImageResponse
): ImageResponse

@GET("api/image")
suspend fun getImages(
@Header("Authorization") token: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.example.mhnfe.data.remote.response



data class ImageResponse(
val result: Result,
val body: ImageResponseBody
)

data class saveImageResponse(
val result: Result,
val body: EmptyBody
)

data class ImageListResponse(
val result: Result,
val body: ImageListBody
Expand All @@ -22,8 +23,9 @@ data class ImageResponseBody(
)

data class ImageListBody(
val images : List<ImageInfo>
val images: List<ImageInfo>
)

data class ImageInfo(
val imageId: Long,
val imageName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ data class CctvInfoResponse(

data class CctvSelfInfoResponse(
val result: Result,
val body : CctvSelfInfoResponseBody
val body: CctvSelfInfoResponseBody
)
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ImageRepositoryImpl @Inject constructor(
private val imageApi: ImageApi,
private val accessTokenDataStore: DataStore<AccessToken>,
private val cctvResponseDataStore: DataStore<CCTVResponseBody>,
): ImageRepository {
) : ImageRepository {

override suspend fun getPresignedUrl(imageName: String): ImageResponse {
val cctvAccessToken = cctvResponseDataStore.data.map { it.accessToken }.first()
Expand All @@ -39,13 +39,14 @@ class ImageRepositoryImpl @Inject constructor(
}
return response
}

override suspend fun saveImage(imageName: String, imagePath: String): saveImageResponse {
val cctvAccessToken = cctvResponseDataStore.data.map { it.accessToken }.first()
val request = ImageSaveRequest(
imageName = imageName,
imagePath = imagePath
)
val response = withContext(Dispatchers.IO) {
val response = withContext(Dispatchers.IO) {
imageApi.imageDevice(
token = cctvAccessToken,
request = request
Expand All @@ -68,6 +69,7 @@ class ImageRepositoryImpl @Inject constructor(
false
}
}

override suspend fun getImages(year: Int, month: String, day: String): ImageListResponse {
val token = accessTokenDataStore.data.map { it.accessToken }.first()
return withContext(Dispatchers.IO) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ object NetworkModule {
fun provideDeviceApi(@Named("default") retrofit: Retrofit): DeviceApi {
return retrofit.create(DeviceApi::class.java)
}

@Provides
@Singleton
fun provideImageApi(@Named("default") retrofit: Retrofit): ImageApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,14 @@ object RepositoryModule {
fun provideTokenRepository(tokenApi: TokenApi) : TokenRepository {
return TokenRepositoryImpl(tokenApi)
}

@Provides
@Singleton
fun provideImageRepository(imageApi: ImageApi, cctvResponseDataStore: DataStore<CCTVResponseBody>,accessTokenDataStore: DataStore<AccessToken>) :ImageRepository {
fun provideImageRepository(
imageApi: ImageApi,
cctvResponseDataStore: DataStore<CCTVResponseBody>,
accessTokenDataStore: DataStore<AccessToken>
): ImageRepository {
return ImageRepositoryImpl(imageApi, accessTokenDataStore, cctvResponseDataStore)
}
}
87 changes: 38 additions & 49 deletions app/src/main/java/com/example/mhnfe/domain/ai/BoundingBoxUtils.kt
Original file line number Diff line number Diff line change
@@ -1,61 +1,50 @@
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<BoundingBox>): 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<BoundingBox>): String =
boundingBoxes.joinToString(prefix = "[", postfix = "]") { box ->
"{\"object_name\":\"${box.objectName}\"}"
// 객체 이름과 신뢰도를 각각 반환하는 메서드
fun getTypeAndConfidence(boundingBoxes: List<BoundingBox>): Pair<String, Float> {
return if (boundingBoxes.isNotEmpty()) {
val box = boundingBoxes.first()
box.objectName to box.cnf
} else {
"unknown" to 0.0f
}
}

fun generateConfidenceJson(boundingBoxes: List<BoundingBox>): String =
boundingBoxes.joinToString(prefix = "[", postfix = "]") { box ->
"{\"confidence\":${box.cnf}}"
// 각 박스의 좌표를 반환하는 메서드
fun getCoordinates(boundingBoxes: List<BoundingBox>): List<Map<String, Int>> {
return boundingBoxes.map { box ->
mapOf(
"x1" to box.x1,
"y1" to box.y1,
"x2" to box.x2,
"y2" to box.y2,
"x3" to box.x1,
"y3" to box.y2,
"x4" to box.x2,
"y4" to box.y1
)
}
}

// 이벤트 발생 여부를 결정하는 메서드
fun shouldTriggerEvent(lastEventTime: Long, eventDelayMillis: Long): Boolean =
(System.currentTimeMillis() - lastEventTime) >= eventDelayMillis
}

// 좌표를 단일 JSON 객체로 변환하는 메서드
fun getFirstCoordinatesAsJson(boundingBoxes: List<BoundingBox>): 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()
} ?: "{}"
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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
)
)
Expand Down Expand Up @@ -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)
}
}
}
38 changes: 19 additions & 19 deletions app/src/main/java/com/example/mhnfe/domain/mqtt/MqttViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -322,32 +322,32 @@ class MqttViewModel @Inject constructor(
fun eventTopic(
trackingId: Int,
objectName: String,
coordinates: String,
confidence: String
confidence: Float,
coordinates: List<Map<String, Int>>
) {
val payload =
val payload = coordinates.firstOrNull().let { coord ->
"""
{
"trackingId": $trackingId,
"timestamp": ${System.currentTimeMillis() / 1000},
"objectType": "$objectName",
"confidence": "$confidence",
"coordinates": $coordinates
}
""".trimIndent()
{
"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()
}

publish("/mhn/event/detect/things/$thingId", payload)
}



private fun publish(topic: String, payload: String) {
try {
awsMqttManager.publishString(payload, topic, AWSIotMqttQos.QOS0)
Log.d(tag, "Published to topic $topic: $payload")
} catch (e: Exception) {
Log.e(tag, "Failed to publish message: ${e.message}", e)
}
awsMqttManager.publishString(payload, topic, AWSIotMqttQos.QOS0)
Log.d(tag, "Published to topic $topic: \n $payload")
}

private fun subscribe(topic: String, onMessageReceived: (String, String) -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import com.example.mhnfe.data.remote.response.saveImageResponse
interface ImageRepository {
suspend fun getPresignedUrl(imageName: String): ImageResponse
suspend fun saveImage(imageName: String, imagePath: String): saveImageResponse
suspend fun uploadToPresignedUrl(presignedUrl: String, imageData: ByteArray) :Boolean
suspend fun uploadToPresignedUrl(presignedUrl: String, imageData: ByteArray): Boolean
suspend fun getImages(year: Int, month: String, day: String): ImageListResponse
}
Loading

0 comments on commit a85f2e6

Please sign in to comment.