完成SCA:蚕茧模块演示效果

This commit is contained in:
BBIT-Kai
2025-06-10 15:32:22 +08:00
parent 89adaf02b9
commit 617cc3162e
19 changed files with 620 additions and 44 deletions
@@ -15,7 +15,8 @@ import io.ktor.server.application.*
import io.ktor.server.tomcat.jakarta.*
const val VIDEO_INPUT_PATH = "/tmp/"
//const val VIDEO_INPUT_PATH = "/tmp/"
const val VIDEO_INPUT_PATH = "C:/tmp/"
/**
* 服务器地址
@@ -16,7 +16,6 @@ object ImageDao {
fun insertImageAnalyticsData(request: ImageAnalyticsRequest) {
return transaction {
ImageTable.insert {
it[object_name] = request.object_name
it[upload_datetime] = Timestamp.valueOf(request.upload_datetime)
.toLocalDateTime().toKotlinLocalDateTime()
it[file_name] = request.file_name
@@ -34,15 +33,19 @@ object ImageDao {
}
fun getVideoList(): List<ImageAnalyticsRequest> {
fun getImageList(name: String): List<ImageAnalyticsRequest> {
return transaction {
ImageTable.selectAll()
.where { ImageTable.name like "%$name%" }
.orderBy(ImageTable.upload_datetime, SortOrder.DESC)
.map {
ImageAnalyticsRequest(
object_name = "http://${SERVER_PATH_OSS}:9000/image/" + it[ImageTable.object_name],
id = it[ImageTable.id].value,
name = it[ImageTable.name],
upload_datetime = formatLocalDateTimeToString(it[ImageTable.upload_datetime]),
file_name = it[ImageTable.file_name],
image_pre = "http://${SERVER_PATH_OSS}:9000/image-sca/" + it[ImageTable.image_pre],
image_after = "http://${SERVER_PATH_OSS}:9000/image-sca/" + it[ImageTable.image_after],
resolution = it[ImageTable.resolution],
size = it[ImageTable.size],
cocoon_count = it[ImageTable.cocoon_count],
@@ -72,7 +72,6 @@ object VideoDao {
}
}
fun getAnalyticsDetailByVideoId(vId: Int): ResultRow? {
return transaction {
VideoTable.selectAll().where { VideoTable.id eq vId }.singleOrNull()
@@ -6,10 +6,12 @@ import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
import org.jetbrains.exposed.v1.datetime.datetime
import org.jetbrains.exposed.v1.json.json
object ImageTable : IntIdTable("image") {
val object_name = varchar("object_name", 255)
object ImageTable : IntIdTable("image_sca") {
val name = varchar("name", 255)
val upload_datetime = datetime("upload_datetime")
val file_name = varchar("file_name", 255)
val image_pre = varchar("image_pre", 255)
val image_after = varchar("image_after", 255)
val resolution = varchar("resolution", 255)
val size = float("size")
val cocoon_count = float("cocoon_count")
@@ -4,10 +4,13 @@ import kotlinx.serialization.Serializable
@Serializable
data class ImageAnalyticsRequest(
val object_name: String, // Minio存储名
val id : Int,
val name : String,
val upload_datetime: String, // 上传时间
val file_name: String, // 文件名
val resolution: String, // 图片分辨率
val image_after: String,
val image_pre: String,
val size: Float, // 文件大小,单位MB
val cocoon_count: Float, // 识别出的茧数量
val max_confidence: Float, // 最大置信度
@@ -9,9 +9,9 @@ import io.ktor.server.routing.*
import io.ktor.server.request.*
import io.ktor.server.response.*
fun Application.ImageAnalytics() {
fun Application.ImageAnalytics() {
routing {
route("/api") {
route("/api/sca") {
// 上传分析结果
post("/saveImageAnalyticsData") {
val request = call.receive<ImageAnalyticsRequest>()
@@ -28,9 +28,10 @@ fun Application.ImageAnalytics() {
stopHLSStream(camera)
call.respond(BaseResponse(message = "摄像头流已停止", data = null))
}
// 获取已分析视频列表
// 获取已分析图片列表
get("/getImageList") {
val res = ImageDao.getVideoList()
val name = call.parameters["name"]
val res = ImageDao.getImageList(name ?: "")
call.respond(BaseResponse(data = res))
}
}
@@ -2,6 +2,7 @@ package ink.snowflake.server.route
import ink.snowflake.server.SERVER_PATH_OSS
import ink.snowflake.server.VIDEO_INPUT_PATH
import ink.snowflake.server.database.VideoDao
import ink.snowflake.server.database.table.VideoTable
import ink.snowflake.server.database.table.VideoTable.vAAverageMaskedRatio
import ink.snowflake.server.database.table.VideoTable.vACountPeople
@@ -12,17 +13,19 @@ import ink.snowflake.server.database.table.VideoTable.vStartDateTime
import ink.snowflake.server.model.request.VideoAnalyticsRequest
import ink.snowflake.server.model.response.*
import ink.snowflake.server.utils.WebSocketManager.broadcastMessage
import ink.snowflake.server.database.VideoDao
import ink.snowflake.server.utils.runCommand
import io.ktor.http.content.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.routing.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.toJavaLocalDateTime
import java.io.File
@@ -67,8 +70,7 @@ fun Application.VideoAnalytics() {
clients.remove(this) // 确保在连接关闭时移除客户端
}
}
route("/api") {
route("/iva") {
route("/api/iva") {
// 上传分析结果
post("/saveVideoAnalyticsData") {
val request = call.receive<VideoAnalyticsRequest>()
@@ -76,7 +78,7 @@ fun Application.VideoAnalytics() {
call.respond(BaseResponse(data = VideoDao.insertVideoAnalyticsData(request)))
}
authenticate {
post("/upload") {
post("/createVideoTask") {
val multipart = call.receiveMultipart() //1G
// 确保 uploads 目录存在
val uploadDir = File(VIDEO_INPUT_PATH)
@@ -90,32 +92,35 @@ fun Application.VideoAnalytics() {
var name = ""
var datetime = ""
broadcastMessage("正在上传数据")
multipart.forEachPart { part ->
when (part) {
is PartData.FileItem -> {
fileName = part.originalFileName ?: "unknown"
val file = File("$VIDEO_INPUT_PATH$fileName") // 保存路径
//ktor3
withContext(Dispatchers.IO) {
multipart.forEachPart { part ->
when (part) {
is PartData.FileItem -> {
fileName = part.originalFileName ?: "unknown"
val file = File("$VIDEO_INPUT_PATH$fileName") // 保存路径
//ktor3
// file.outputStream().use { outputStream ->
// val writableChannel = Channels.newChannel(outputStream)
// part.provider().copyTo(writableChannel) // 复制到 WritableByteChannel
// }
//ktor2
part.streamProvider().use { inputStream ->
file.outputStream().buffered().use { outputStream ->
inputStream.copyTo(outputStream)
//ktor2
part.streamProvider().use { inputStream ->
file.outputStream().buffered().use { outputStream ->
inputStream.copyTo(outputStream)
}
}
}
}
is PartData.FormItem -> {
when (part.name) {
"name" -> name = part.value
"datetime" -> datetime = part.value
is PartData.FormItem -> {
when (part.name) {
"projectName" -> name = part.value
"projectDatetime" -> datetime = part.value
}
}
}
else -> part.dispose()
else -> part.dispose()
}
}
}
call.respond(BaseResponse(message = "上传成功", data = null))
@@ -267,7 +272,6 @@ fun Application.VideoAnalytics() {
)
}
}
}
}
}
}