Browse Source

add 提交

master
lucas 3 weeks ago
parent
commit
3446c61c14
  1. 15
      MyOpenCv/.gitignore
  2. 1
      MyOpenCv/app/.gitignore
  3. 88
      MyOpenCv/app/build.gradle.kts
  4. 21
      MyOpenCv/app/proguard-rules.pro
  5. 84
      MyOpenCv/app/src/androidTest/java/com/example/myopencv/ExampleInstrumentedTest.kt
  6. 46
      MyOpenCv/app/src/main/AndroidManifest.xml
  7. 311
      MyOpenCv/app/src/main/java/com/example/myopencv/MainActivity.kt
  8. 77
      MyOpenCv/app/src/main/java/com/example/myopencv/UdpServer.kt
  9. 262
      MyOpenCv/app/src/main/java/com/example/myopencv/camera.kt
  10. 90
      MyOpenCv/app/src/main/java/com/example/myopencv/configLoad.kt
  11. 277
      MyOpenCv/app/src/main/java/com/example/myopencv/dataProcess.kt
  12. 286
      MyOpenCv/app/src/main/java/com/example/myopencv/dataTrans.kt
  13. 43
      MyOpenCv/app/src/main/java/com/example/myopencv/fileUtils.kt
  14. 19
      MyOpenCv/app/src/main/java/com/example/myopencv/models/centroidData.kt
  15. 15
      MyOpenCv/app/src/main/java/com/example/myopencv/models/command.kt
  16. 39
      MyOpenCv/app/src/main/java/com/example/myopencv/models/mSetting.kt
  17. 17
      MyOpenCv/app/src/main/java/com/example/myopencv/models/sensor.kt
  18. 19
      MyOpenCv/app/src/main/java/com/example/myopencv/models/sensorData.kt
  19. 40
      MyOpenCv/app/src/main/java/com/example/myopencv/models/uploadData.kt
  20. 12
      MyOpenCv/app/src/main/java/com/example/myopencv/models/userInfo.kt
  21. 224
      MyOpenCv/app/src/main/java/com/example/myopencv/tcpServer.kt
  22. 11
      MyOpenCv/app/src/main/java/com/example/myopencv/ui/theme/Color.kt
  23. 58
      MyOpenCv/app/src/main/java/com/example/myopencv/ui/theme/Theme.kt
  24. 34
      MyOpenCv/app/src/main/java/com/example/myopencv/ui/theme/Type.kt
  25. 181
      MyOpenCv/app/src/main/java/imageHandler.kt
  26. 170
      MyOpenCv/app/src/main/res/drawable/ic_launcher_background.xml
  27. 30
      MyOpenCv/app/src/main/res/drawable/ic_launcher_foreground.xml
  28. BIN
      MyOpenCv/app/src/main/res/drawable/xml_4.jpg
  29. BIN
      MyOpenCv/app/src/main/res/drawable/yu_5.jpg
  30. BIN
      MyOpenCv/app/src/main/res/drawable/zp_1.png
  31. 6
      MyOpenCv/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  32. 6
      MyOpenCv/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  33. BIN
      MyOpenCv/app/src/main/res/mipmap-hdpi/ic_launcher.webp
  34. BIN
      MyOpenCv/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
  35. BIN
      MyOpenCv/app/src/main/res/mipmap-mdpi/ic_launcher.webp
  36. BIN
      MyOpenCv/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
  37. BIN
      MyOpenCv/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
  38. BIN
      MyOpenCv/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
  39. BIN
      MyOpenCv/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
  40. BIN
      MyOpenCv/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
  41. BIN
      MyOpenCv/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
  42. BIN
      MyOpenCv/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
  43. 10
      MyOpenCv/app/src/main/res/values/colors.xml
  44. 4
      MyOpenCv/app/src/main/res/values/strings.xml
  45. 5
      MyOpenCv/app/src/main/res/values/themes.xml
  46. 13
      MyOpenCv/app/src/main/res/xml/backup_rules.xml
  47. 19
      MyOpenCv/app/src/main/res/xml/data_extraction_rules.xml
  48. 137
      MyOpenCv/app/src/main/res/图片.txt
  49. 122
      MyOpenCv/app/src/test/java/com/example/myopencv/ExampleUnitTest.kt
  50. 5
      MyOpenCv/build.gradle.kts
  51. 23
      MyOpenCv/gradle.properties
  52. 40
      MyOpenCv/gradle/libs.versions.toml
  53. 6
      MyOpenCv/gradle/wrapper/gradle-wrapper.properties
  54. 185
      MyOpenCv/gradlew
  55. 89
      MyOpenCv/gradlew.bat
  56. 193
      MyOpenCv/opencv/build.gradle
  57. 24
      MyOpenCv/settings.gradle

15
MyOpenCv/.gitignore

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

1
MyOpenCv/app/.gitignore

@ -0,0 +1 @@
/build

88
MyOpenCv/app/build.gradle.kts

@ -0,0 +1,88 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
kotlin("plugin.serialization") version "2.1.0"
}
android {
namespace = "com.example.myopencv"
compileSdk = 34
defaultConfig {
applicationId = "com.example.myopencv"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(project(":opencv"))
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
dependencies {
// Camerax implementation
//def cameraxVersion = "1.3.1"
implementation (libs.camera.core)
implementation (libs.androidx.camera.camera.camera22)
implementation (libs.androidx.camera.camera.view)
implementation (libs.camera.lifecycle)
// Camerax implementation
}
dependencies {
implementation(libs.core.ktx)
implementation(libs.kotlinx.serialization.json)
}

21
MyOpenCv/app/proguard-rules.pro

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

84
MyOpenCv/app/src/androidTest/java/com/example/myopencv/ExampleInstrumentedTest.kt

@ -0,0 +1,84 @@
package com.example.myopencv
import android.content.Context
import android.graphics.BitmapFactory
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
import org.opencv.android.Utils
import org.opencv.core.CvType
import org.opencv.core.Mat
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.myopencv", appContext.packageName)
}
@Test
fun testLoadBitmapFromResource() {
//照片选取 计算后的xReal=-127.2813 yReal=94.4458
//测点区域 x=97,y=1054,w=569,z=425
// 质心 x=-284.0299 , y=210.900
val imageResourceId =R.drawable.zp_127_245___210_90
val options = BitmapFactory.Options()
options.inScaled = false
// 获取应用程序上下文
val context: Context = ApplicationProvider.getApplicationContext()
val rawBitmap = BitmapFactory.decodeResource(context.resources, imageResourceId,options)
val rawMat = Mat(rawBitmap.width, rawBitmap.height, CvType.CV_8UC3)
Utils.bitmapToMat(rawBitmap, rawMat)
//灰度
val garyMat =imageHandler.mat2gary(rawMat)
val garyBitmap = imageHandler.mat2bitMap(garyMat)
//二值化
val thresholdValue=128.0
val binaryBitmap=imageHandler.binaryBitMap(thresholdValue,garyMat)
//图像截取 取值实际配置的区域参数
var x=97
var y=1054
var w=569
var h=425
val subMat=imageHandler.cropMat(rawMat,x,y,w,h)
val subBitMat= imageHandler.mat2bitMap(subMat)
val subGary=imageHandler.mat2gary(subMat)
val binaryThreshold=30.0
val subBinary=imageHandler.binaryMat(binaryThreshold,subGary)
val center=imageHandler.calcMoments(subBinary)
println("center数据= $center")
}
}
class ConfigLoadTest {
@Test
fun useAppContext() {
// Context of the app under test.
// val appContext = InstrumentationRegistry.getInstrumentation().targetContext
// val info=UserInfo(2017,"lucas","249324454@qq.com","male")
// SharedPrefs.saveUserToPreferences(appContext,info)
// val infoRead=SharedPrefs.loadUserFromPreferences(appContext)
// assertEquals(info, infoRead)
}
}

46
MyOpenCv/app/src/main/AndroidManifest.xml

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyOpenCv"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.MyOpenCv">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyTcpServer"
android:enabled="true"
android:exported="true">
</service>
<service
android:name=".UdpServer"
android:enabled="true"
android:exported="true">
</service>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>

311
MyOpenCv/app/src/main/java/com/example/myopencv/MainActivity.kt

@ -0,0 +1,311 @@
package com.example.myopencv
import ImageHandler
import android.Manifest
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import com.example.myopencv.ui.theme.MyOpenCvTheme
import org.opencv.android.OpenCVLoader
import org.opencv.android.Utils
import org.opencv.core.CvType
import org.opencv.core.Mat
import org.opencv.core.Scalar
import org.opencv.imgproc.Imgproc
val imageHandler = ImageHandler()
lateinit var myTcpSvc: MyTcpServer
lateinit var myUdpSvc: UdpServer
val deflectometer= Deflectometer()
class MainActivity : ComponentActivity() {
private var binderTcp: MyTcpServer.LocalBinder? = null
private var binderUdp: UdpServer.LocalBinder? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val configContent=fileUtils.readerFile(this,"settings.json")
deflectometer.defaultSet(configContent)
val isOk=OpenCVLoader.initLocal()
if (isOk){
Toast.makeText(this,"opencv加载成功",Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(this,
"opencv加载失败,退出",
Toast.LENGTH_SHORT).show()
finish()
}
applyForPermission()
val serviceIntentTcp = Intent(this, MyTcpServer::class.java)
bindService(serviceIntentTcp, serviceConnectionTcp, Context.BIND_AUTO_CREATE)
val serviceIntentUdp = Intent(this, UdpServer::class.java)
bindService(serviceIntentUdp, serviceConnectionUdp, Context.BIND_AUTO_CREATE)
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) -> {
setCameraPreview()
}
}
}
private val serviceConnectionTcp = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, iBService: IBinder) {
//绑定到服务,可以获取服务中的Binder实例
binderTcp = iBService as MyTcpServer.LocalBinder
myTcpSvc = binderTcp!!.getService()
}
override fun onServiceDisconnected(arg0: ComponentName) {
binderTcp = null
}
}
private val serviceConnectionUdp = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, iBService: IBinder) {
//绑定到服务,可以获取服务中的Binder实例
binderUdp = iBService as UdpServer.LocalBinder
myUdpSvc = binderUdp!!.getService()
}
override fun onServiceDisconnected(arg0: ComponentName) {
binderUdp = null
}
}
private val cameraPermissionRequest =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
setCameraPreview()
Log.i("权限","同意授予")
} else {
// Camera permission denied
Log.i("权限","拒绝授予")
}
}
private fun setImageHandler() {
setContent {
MyOpenCvTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android,来了",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
private fun setCameraPreview() {
setContent {
CameraPreviewScreen()
}
}
private fun applyForPermission(){
if (ContextCompat.checkSelfPermission(
this, Manifest.permission.WRITE_EXTERNAL_STORAGE
)!=PackageManager.PERMISSION_GRANTED ) {
cameraPermissionRequest.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
Log.i("权限", "请求外部存储")
}
if (ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
)!= PackageManager.PERMISSION_GRANTED ) {
cameraPermissionRequest.launch(Manifest.permission.CAMERA)
Log.i("权限", "请求相机")
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
//照片选取
var result by remember { mutableIntStateOf(2) }
val imageResource = when (result) {
1 -> R.drawable.zp_1
else -> R.drawable.yu_5
}
val options = BitmapFactory.Options()
options.inScaled = false
val rawBitmap = BitmapFactory.decodeResource(LocalContext.current.resources, imageResource,options)
val rawMat =Mat(rawBitmap.width, rawBitmap.height, CvType.CV_8UC3)
Utils.bitmapToMat(rawBitmap, rawMat)
//灰度
val garyMat =imageHandler.mat2gary(rawMat)
val garyBitmap = imageHandler.mat2bitMap(garyMat)
//二值化
val thresholdValue=128.0
val binaryBitmap=imageHandler.binaryBitMap(thresholdValue,garyMat)
//图像截取 取值实际配置的区域参数
var x=600
var y=600
var w=252
var h=186
if (result==2 ||result==6){
x=97
y=1054
w=569
h=425
}
//用外包方式的计算质心
val viewRect=android.graphics.Rect(x,y,x+w-1,y+h-1)
val wbc=imageHandler.getBinImageCentroid(rawBitmap,30,viewRect)
//
val subMat=imageHandler.cropMat(rawMat,x,y,w,h)
val subBitMat= imageHandler.mat2bitMap(subMat)
val subGary=imageHandler.mat2gary(subMat)
val binaryThreshold=30.0
val subBinary=imageHandler.binaryMat(binaryThreshold,subGary)
val center=imageHandler.calcMoments(subBinary)
//测试
// val deflectometer= Deflectometer()
// val cp= CentroidPoint(center.x,center.y)
// val centroidDataArray= CentroidData("", arrayOf(cp))
// val r=deflectometer.dataProcess(centroidDataArray)
// println("挠度数据= $r")
//测试
// 在原图像上标记质心
Imgproc.circle(subMat, center, 5, Scalar(0.0, 0.0, 255.0), 2)
val centerBitMap=imageHandler.mat2bitMap(subMat)
LazyColumn(
modifier = Modifier
.fillMaxSize()
.wrapContentSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
item {
Image(
painter = painterResource(imageResource),
contentDescription = result.toString(),
Modifier.size(300.dp),
contentScale = ContentScale.Fit
)
Image(
bitmap = garyBitmap.asImageBitmap(),
contentDescription = "灰度",
Modifier.size(300.dp),
contentScale = ContentScale.Fit
)
Button(onClick = {
result = (1..7).random()
}) {
Text("灰化效果")
}
}
item {
HorizontalDivider(color = Color(0.1f, 0.8f, 0.9f, 1.0f))
Image(
bitmap = binaryBitmap.asImageBitmap(),
contentDescription = "二值化",
Modifier.size(300.dp),
contentScale = ContentScale.Fit
)
}
item {
Image(
bitmap = subBitMat.asImageBitmap(),
contentDescription = "区域截取",
Modifier.size(300.dp),
contentScale = ContentScale.Fit
)
}
item {
Image(
bitmap = imageHandler.mat2bitMap(subGary).asImageBitmap(),
contentDescription = "区域灰度",
Modifier.size(300.dp),
contentScale = ContentScale.Fit
)
}
item {
Image(
bitmap = centerBitMap.asImageBitmap(),
contentDescription = "质心标记",
Modifier.size(300.dp),
contentScale = ContentScale.Fit
)
}
item {
Text("底部,没有了")
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyOpenCvTheme {
//Greeting("Android")
}
}

77
MyOpenCv/app/src/main/java/com/example/myopencv/UdpServer.kt

@ -0,0 +1,77 @@
package com.example.myopencv
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
class UdpServer:Service(){
// 内部Binder类
inner class LocalBinder : Binder() {
// 返回TcpService的实例
fun getService(): UdpServer = this@UdpServer
}
private val binder = LocalBinder()
override fun onBind(intent: Intent?): IBinder {
println("==onBind")
return binder
}
override fun onCreate() {
super.onCreate()
Thread(runnable).start()
println("启动 udp runnable")
}
override fun onDestroy() {
super.onDestroy()
Log.d("data","-> onDestroy")
}
private var runnable= kotlinx.coroutines.Runnable {
udpWork()
}
private fun udpWork(){
val serverSocket= DatagramSocket(2230)
println(serverSocket.localSocketAddress)
println(serverSocket.localAddress)
while (true) {
val buffer = ByteArray(102)
val packet = DatagramPacket(buffer, buffer.size)
serverSocket.receive(packet)
val remoteAddress = packet.address
val remotePort = packet.port
val recvMsg = String(packet.data, 0, packet.length)
// 创建应答数据
val responseMsg=decodeCmd(recvMsg,this)
val response = responseMsg.toByteArray()
// 发送应答
val responsePacket = DatagramPacket(response, response.size, remoteAddress, remotePort)
serverSocket.send(responsePacket)
println("收到${remoteAddress}:${remotePort}搜索设备命令${recvMsg}")
println("应答搜索${responseMsg}")
}
}
private fun sendData(msg:String,ip:String){
val socket = DatagramSocket()
val address = InetAddress.getByName(ip)
val port = 2230
val data = msg.toByteArray()
val packet = DatagramPacket(data, data.size, address, port)
socket.send(packet)
socket.close()
println("发送完毕")
}
}

262
MyOpenCv/app/src/main/java/com/example/myopencv/camera.kt

@ -0,0 +1,262 @@
package com.example.myopencv
import ImageHandler
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Rect
import android.icu.text.SimpleDateFormat
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.core.resolutionselector.ResolutionSelector
import androidx.camera.core.resolutionselector.ResolutionStrategy
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import com.example.myopencv.models.CentroidData
import com.example.myopencv.models.UData
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.util.Locale
import java.util.concurrent.Executors
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@Composable
fun CameraPreviewScreen() {
val imageHandler = ImageHandler()
val cameraExecutor=Executors.newSingleThreadExecutor()
val lensFacing = CameraSelector.LENS_FACING_BACK
val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current
// val previewView = remember {
// PreviewView(context)
// }
val cameraxSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
// val imageCapture = remember {
// ImageCapture.Builder().build()
// }
val timeStampState= remember { mutableLongStateOf(0) }
val xView= remember { mutableDoubleStateOf(0.0) }
val yView= remember { mutableDoubleStateOf(0.0) }
//var centroidObj by remember { mutableStateOf(0.0) }
// val rawMat = Mat(2112, 1568, CvType.CV_8UC3)
// val options = BitmapFactory.Options()
// options.inScaled = false
val rawBitmap = BitmapFactory.decodeResource(LocalContext.current.resources, R.drawable.yu_5)
val yuMap= remember { mutableStateOf(rawBitmap) }
//val preview = Preview.Builder().build()
val imageAnalyzer = ImageAnalysis.Builder()
.setResolutionSelector(
ResolutionSelector.Builder().
setResolutionStrategy(ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY)
//.setAspectRatioStrategy(AspectRatioStrategy.RATIO_16_9_FALLBACK_AUTO_STRATEGY)
.build()
)
.build()
.also {
it.setAnalyzer(cameraExecutor, GdndAnalyzer { img ->
val imageBitMapRaw=img.toBitmap()
//缓存bitmap 用于图像上传
val rotation = img.imageInfo.rotationDegrees //180
//println("角度信息: $rotation")
val imageBitMap=imageHandler.rotateBitmap(imageBitMapRaw, rotation.toFloat())
val grayBitMap=imageHandler.bitMap2Gray(imageBitMap)
yuMap.value=imageBitMap
timeStampState.longValue=System.currentTimeMillis()
val timeStr=timeNow2string()
val centroidDataArray= CentroidData(timeStr, mutableListOf())
val threshold=deflectometer.readThreshold()
deflectometer.readSensor().forEach{ s ->
val x=s.x.toInt()
val y=s.y.toInt()
val w=s.w.toInt()
val h=s.h.toInt()
//cv计算
//val p=imageHandler.img2Moments(img,threshold,x,y,w,h)
//外包计算方式
val viewRect= Rect(x,y,x+w-1,y+h-1)
val p=imageHandler.getBinImageCentroid(imageBitMap,threshold,viewRect)
//Log.d("传感器[${s.pos}] ${s.des}", "计算图像[w=${img.width},h=${img.height}]质心${p}")
centroidDataArray.centroids.add(p)
}
myTcpSvc.cacheImage(grayBitMap)
val mResult=deflectometer.dataProcess(centroidDataArray)
// val uploadData=result2uData(mResult)
// val uploadDataJson=Json.encodeToString<UData>(uploadData)
// myTcpSvc.send2All(uploadDataJson)
// //preview显示首个测点数据
// if (mResult.sensorsData.size>0){
// xView.doubleValue=mResult.sensorsData[0].xReal
// yView.doubleValue=mResult.sensorsData[0].yReal
// }
0.0
})
}
LaunchedEffect(lensFacing) {
val cameraProvider = context.getCameraProvider()
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraxSelector, imageAnalyzer)
//注意实际运行的时候 注释preview
//preview.setSurfaceProvider(previewView.surfaceProvider)
}
Box(contentAlignment = Alignment.BottomCenter, modifier = Modifier.fillMaxSize()) {
//AndroidView({ previewView }, modifier = Modifier.fillMaxSize())
Column(
modifier = Modifier
.padding(horizontal = 20.dp)
.safeDrawingPadding(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = time2string(timeStampState.longValue),
color = Color.Green,
fontSize = 30.sp
)
Text(
text = "xReal= ${String.format(Locale.CHINA,"%.5f", xView.doubleValue)}\nyReal= ${String.format(Locale.CHINA,"%.5f", yView.doubleValue)}",
color = Color.Green,
fontSize = 30.sp
)
Image(
bitmap = yuMap.value.asImageBitmap(),
contentDescription = "图像区域截取",
Modifier.size(500.dp),
contentScale = ContentScale.Fit
)
Button(
onClick = {
//captureImage(imageCapture, context)
}
) {
Text(text = "抓拍")
}
Spacer(Modifier.size(60.dp))
}
}
}
private fun captureImage(imageCapture: ImageCapture, context: Context) {
val tName= timeNow2string()
val dirName="光电"
val name = "${dirName}_${tName}.jpeg"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "光电抓拍拍")
}
}
val outputOptions = ImageCapture.OutputFileOptions
.Builder(
context.contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
.build()
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(context),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Log.i("照片存储","Successes")
}
override fun onError(exception: ImageCaptureException) {
Log.i("照片存储","Failed $exception")
}
})
}
private suspend fun Context.getCameraProvider(): ProcessCameraProvider =
suspendCoroutine { continuation ->
ProcessCameraProvider.getInstance(this).also { cameraProvider ->
cameraProvider.addListener({
continuation.resume(cameraProvider.get())
}, ContextCompat.getMainExecutor(this))
}
}
fun timeNow2string() :String{
val sf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS",Locale.CHINA)
return sf.format(System.currentTimeMillis())
}
private fun time2string(timeStamp:Long) :String{
val sf = SimpleDateFormat("yyyyMMdd_HHmmss.SSS",Locale.CHINA)
return sf.format(timeStamp)
}
private class GdndAnalyzer(private val listener: imageListener) : ImageAnalysis.Analyzer {
override fun analyze(image: ImageProxy) {
//图像处理
//Log.i("图像处理","处理图片帧")
listener(image)
image.close()
}
}
typealias imageListener = (img: ImageProxy) -> Double

90
MyOpenCv/app/src/main/java/com/example/myopencv/configLoad.kt

@ -0,0 +1,90 @@
package com.example.myopencv
import android.content.Context
import android.content.SharedPreferences
import com.example.myopencv.models.UserInfo
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
object SharedPrefs {
private const val TOKEN_PREF = "TOKEN_PREF"
private const val TOKEN_KEY = "TOKEN_KEY"
private fun getPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(TOKEN_PREF, Context.MODE_PRIVATE)
}
// 存储单个值
// 调用 : SharedPrefs.setToken(this@MyActivity, "123456")
fun setToken(context: Context, token: String) {
val editor = getPreferences(context).edit()
editor.putString(TOKEN_KEY, token)
editor.apply()
}
// 获取单个值
// 调用 : token = SharedPrefs.getToken(this@MyActivity)
fun getToken(context: Context?): String? {
return context?.let { getPreferences(it).getString(TOKEN_KEY, null) }
}
// 移除单个值
// 调用SharedPrefs.removeToken(this@MyActivity)
fun removeToken(context: Context?) {
context?.let { getPreferences(it).edit().remove(TOKEN_KEY).apply() }
}
// 存储userInfo对象
// 调用 : SharedPrefs.saveUserToPreferences(this@MyActivity, jsonElement)
fun saveUserToPreferences(context: Context, userinfo: UserInfo) {
val json = Json.encodeToString(userinfo)
val sharedPreferences = context.getSharedPreferences("UserPrefs", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putString("userinfo", json)
editor.apply()
}
// 获取userInfo对象缓存
// 调用 : userInfo = SharedPrefs.loadUserFromPreferences(this@MyActivity) userId = userInfo .id
fun loadUserFromPreferences(context: Context): UserInfo {
val sharedPreferences = context.getSharedPreferences("UserPrefs", Context.MODE_PRIVATE)
val json = sharedPreferences.getString("userinfo", "")
val userInfo = Json.decodeFromString<UserInfo>(json?:"")
return userInfo
}
// 更新userInfo对象某个字段
// 调用 : SharedPrefs.setUserInfo(this@MyActivity, "username", "alic")
fun setUserInfo(context: Context, editName: String, editValue: String) {
val sharedPreferences = context.getSharedPreferences("UserPrefs", Context.MODE_PRIVATE)
val json = sharedPreferences.getString("userinfo", "")
val myObject1 = Json.decodeFromString<UserInfo>(json?:"")
val editor = sharedPreferences.edit()
if (editName == "username") {
myObject1.username = editValue
}else if (editName == "email") {
myObject1.email = editValue
}else if (editName == "sex") {
myObject1.sex = editValue
}
val myObject2 = Json.encodeToString(myObject1)
editor.putString("userinfo", myObject2)
println("更新后的个人信息 : $myObject2")
editor.apply()
}
// 清除所有缓存
// 调用 : SharedPrefs.clearAllData(this@MyActivity)
fun clearAllData(context: Context) {
val preferences = context.getSharedPreferences("UserPrefs", Context.MODE_PRIVATE)
val editor = preferences.edit()
removeToken(context)
editor.clear()
editor.apply()
}
}

277
MyOpenCv/app/src/main/java/com/example/myopencv/dataProcess.kt

@ -0,0 +1,277 @@
package com.example.myopencv
import com.example.myopencv.models.CentroidData
import com.example.myopencv.models.SensorData
import com.example.myopencv.models.ManSetting2
import com.example.myopencv.models.Sensor
import kotlinx.serialization.*
@Serializable
data class MResult(
var sensorsData: MutableList<SensorData>,
var timestamp:String
)
class Deflectometer {
var imageSendEnabled=true
var isClearZero=false
private var m_settings = ManSetting2()
var m_result = MResult(mutableListOf(),"")
fun dataProcess(data: CentroidData) :MResult {
// 从设置中获取零点计数,并确保其至少为1
var zeroCount = m_settings.baseParam.zeroCount
zeroCount = if (zeroCount <= 0) 1 else zeroCount
// 获取是否清除零点的标志
// 获取无效数据计数
val invalidDataCount = m_settings.baseParam.invalidDataCount
// 获取传感器数组
val t_sensors = m_settings.sensors
// 获取结果中的传感器数组
val sensorDataList = m_result.sensorsData
// 获取数据的时间戳
val timestamp = data.timestampStr
// 获取质心数组
val centroids = data.centroids
// 遍历质心数组
for (i in centroids.indices) {
val centroid = centroids[i]
val xCur = centroid.x
val yCur = centroid.y
if (i < sensorDataList.size && i < t_sensors.size) {
val sensorData = sensorDataList[i]
val t_sensor = t_sensors[i]
var invalidCount = sensorData.invalidCount
// 如果当前质心为(0,0)
if (xCur == 0.0 && yCur == 0.0) {
if (invalidCount < invalidDataCount) {
invalidCount++
}
} else {
if (invalidCount > 0) {
invalidCount--
} else {
sensorData.xCur = xCur
sensorData.yCur = yCur
var xAvg = sensorData.xAvg
var yAvg = sensorData.yAvg
// 计算平均值
xAvg = if (xAvg == 0.0) xCur else (xAvg * (zeroCount - 1) + xCur) / (zeroCount*1.0)
yAvg = if (yAvg == 0.0) yCur else (yAvg * (zeroCount - 1) + yCur) / (zeroCount*1.0)
sensorData.xAvg = xAvg
sensorData.yAvg = yAvg
// 如果需要清除零点
if (isClearZero) {
sensorData.xZero = xAvg
sensorData.yZero = yAvg
t_sensor.xZero = xAvg
t_sensor.yZero = yAvg
}
val xZero = sensorData.xZero
val yZero = sensorData.yZero
val xTemp = xCur - xZero
val yTemp = yCur - yZero
sensorData.xTemp = xTemp
sensorData.yTemp = yTemp
}
}
sensorData.invalidCount = invalidCount
sensorDataList[i] = sensorData
t_sensors[i] = t_sensor
}
}
m_settings.sensors=t_sensors
// 重置清除零点
if (isClearZero) {
isClearZero = false
}
var xBase = 0.0
var yBase = 0.0
// 查找基准传感器
for (i in sensorDataList.indices) {
val sensor = sensorDataList[i]
if (sensor.sensor.tar == "y") {
xBase = sensor.xTemp
yBase = sensor.yTemp
break
}
}
// 获取结果计数
var resultCount = m_settings.baseParam.resultCount
resultCount = if (resultCount <= 0) 1 else resultCount
// 遍历传感器数组进行计算
for (i in sensorDataList.indices) {
val sensor = sensorDataList[i]
val invalidCount = sensor.invalidCount
if (invalidCount > 0) {
if (invalidCount >= invalidDataCount) {
sensor.xReal = Double.NaN
sensor.yReal = Double.NaN
}
} else {
val arg = sensor.sensor.arg.toDouble()
val xTemp = sensor.xTemp
val yTemp = sensor.yTemp
val xReal = sensor.xReal
val yReal = sensor.yReal
// 计算实际值
val xVal = (xTemp - xBase) * arg
val yVal = (yTemp - yBase) * arg
val xAvg = if (sensor.xReal.isNaN()) xVal else ((resultCount - 1) * xReal + xVal) / resultCount
val yAvg = if (sensor.yReal.isNaN()) yVal else ((resultCount - 1) * yReal + yVal) / resultCount
sensor.xReal = xAvg
sensor.yReal = yAvg
}
sensorDataList[i] = sensor
}
m_result.sensorsData = sensorDataList
m_result.timestamp = timestamp
return m_result
}
fun readResult():MResult{
return m_result
}
fun defaultSet(configStr:String){
m_settings = ManSetting2(
sensors = mutableListOf()
)
if (configStr!="") {
m_settings = json.decodeFromString<ManSetting2>(configStr)
}else {
m_settings.sensors.add(
Sensor(
arg = "0.448",
des = "default",
pos = "1",
tar = "n",
x = "97",
y = "1054",
h = "425",
w = "569",
xZero = 0.0,
yZero = 0.0
)
)
}
defaultSensorsData()
}
private fun defaultSensorsData(){
m_result.sensorsData= mutableListOf()
m_settings.sensors.forEach {
val sd = SensorData(sensor = it)
sd.xZero=it.xZero
sd.yZero=it.yZero
m_result.sensorsData.add(sd)
}
}
fun readSensor():List<Sensor>{
return m_settings.sensors
}
fun updateSensor(sensorList: MutableList<Sensor>):ManSetting2{
//纪录之前Zero
for(i in 0 until sensorList.size){
m_settings.sensors.forEach {
if(it.pos==sensorList[i].pos){
sensorList[i].xZero=it.xZero
sensorList[i].yZero=it.yZero
}
}
}
m_settings.sensors=sensorList
defaultSensorsData()
return m_settings
}
fun updateThreshold(t:Int):ManSetting2{
m_settings.baseParam.threshold=t
return m_settings
}
fun readThreshold():Int{
return m_settings.baseParam.threshold
}
fun updateInvalidDataCount(t:Int):ManSetting2{
m_settings.baseParam.invalidDataCount=t
return m_settings
}
fun readInvalidDataCount():Int{
return m_settings.baseParam.invalidDataCount
}
fun updateImageSendTime(t:Int):ManSetting2{
m_settings.baseParam.imageSendTime=t
return m_settings
}
fun readImageSendTime():Int{
return m_settings.baseParam.imageSendTime
}
fun updateZeroCount(t:Int):ManSetting2{
m_settings.baseParam.zeroCount=t
return m_settings
}
fun readZeroCount():Int{
return m_settings.baseParam.zeroCount
}
fun updateResultCount(t:Int):ManSetting2{
m_settings.baseParam.resultCount=t
return m_settings
}
fun readResultCount():Int{
return m_settings.baseParam.resultCount
}
fun updateDataFps(t:Int):ManSetting2{
var interval=t
if (interval<=0){
interval=1
}
m_settings.baseParam.dataFPS=interval
return m_settings
}
fun readDataFps():Int{
return m_settings.baseParam.dataFPS
}
fun updateVideoFps(t:Int):ManSetting2{
m_settings.baseParam.videoFPS=t
return m_settings
}
fun readVideoFps():Int{
return m_settings.baseParam.videoFPS
}
fun updateClearZero(set: Boolean):ManSetting2 {
isClearZero=set
//更新配置
for (i in 0 until m_settings.sensors.size) {
val pos=m_settings.sensors[i].pos
m_result.sensorsData.forEach {
if (it.sensor.pos==pos){
m_settings.sensors[i].xZero=it.xAvg
m_settings.sensors[i].yZero=it.yAvg
}
}
}
return m_settings
}
}

286
MyOpenCv/app/src/main/java/com/example/myopencv/dataTrans.kt

@ -0,0 +1,286 @@
package com.example.myopencv
import android.content.Context
import com.example.myopencv.models.UData
import com.example.myopencv.models.USensor
import com.example.myopencv.models.URealValue
import java.io.ByteArrayOutputStream
import android.graphics.Bitmap
import android.util.Base64
import com.example.myopencv.models.Command
import com.example.myopencv.models.ManSetting2
import com.example.myopencv.models.Sensor
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
fun result2uData(r:MResult):UData{
val uValue=URealValue(
timestamp = r.timestamp,
sensors = mutableListOf()
)
r.sensorsData.forEach {
uValue.sensors.add(
USensor(
arg = it.sensor.arg,
des = it.sensor.des,
pos = it.sensor.pos,
tar = it.sensor.tar,
xReal = if (it.xReal.isNaN()) null else it.xReal,
yReal = if (it.yReal.isNaN()) null else it.yReal,
)
)
}
return UData(
command = "result",
type = "reply",
values = uValue
)
}
fun bitmapToBase64(bitmap: Bitmap): String {
// 创建一个ByteArrayOutputStream
val byteArrayOutputStream = ByteArrayOutputStream()
// 将Bitmap压缩为PNG格式并写入到ByteArrayOutputStream
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream)
// 将压缩后的数据转换为字节数组
val bytes = byteArrayOutputStream.toByteArray()
// 使用Base64进行编码
// 这里的 Base64.NO_WRAP 参数表示不将编码结果分割为多行
val base64Image = Base64.encodeToString(bytes,Base64.NO_WRAP)
// 关闭ByteArrayOutputStream
byteArrayOutputStream.close()
// 返回Base64编码的字符串
return base64Image
}
fun decodeCmd(cmdStr:String,ctx:Context):String{
val command = json.decodeFromString<Command>(cmdStr)
var reply=""
when(command.command) {
"sensors" -> {
when (command.type) {
//传感器信息获取
"get" -> {
val s=Json.encodeToString(deflectometer.readSensor())
val replyCommand=Command(
command = command.command,
type = command.type,
values = Json.parseToJsonElement(s)
)
reply = Json.encodeToString(replyCommand)
}
"set" -> {
val sensorSetStr = command.values.jsonArray.toString()
val sensors = json.decodeFromString<MutableList<Sensor>>(sensorSetStr)
val mSet = deflectometer.updateSensor(sensors)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"sensors","type":"set","values":"ok"}"""
}
}
}
"imageSendEnabled" ->{
when (command.type) {
//信息获取
"set" -> {
val imageSendEnabled = command.values.jsonPrimitive.boolean
deflectometer.imageSendEnabled=imageSendEnabled
reply = """{"command":"imageSendEnabled","type":"set","values":"ok"}"""
}
}
}
"isClearZero" ->{
when (command.type) {
//信息获取
"set" -> {
val isClearZero=command.values.jsonPrimitive.boolean
val mSet=deflectometer.updateClearZero(isClearZero)
val mSetStr=json.encodeToString(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"isClearZero","type":"set","values":"ok"}"""
}
}
}
"threshold" ->{
when (command.type) {
"set" -> {
val threshold=command.values.jsonPrimitive.int
val mSet=deflectometer.updateThreshold(threshold)
val mSetStr=json.encodeToString(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"isClearZero","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readThreshold()
reply = """{"command":"threshold","type":"get","values":${t}}"""
}
}
}
"invalidDataCount" ->{
when (command.type) {
"set" -> {
val invalidDataCount=command.values.jsonPrimitive.int
val mSet=deflectometer.updateInvalidDataCount(invalidDataCount)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"invalidDataCount","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readInvalidDataCount()
reply = """{"command":"invalidDataCount","type":"get","values":${t}}"""
}
}
}
"imageSendTime" ->{
when (command.type) {
"set" -> {
val imageSendTime=command.values.jsonPrimitive.int
val mSet=deflectometer.updateImageSendTime(imageSendTime)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"imageSendTime","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readImageSendTime()
reply = """{"command":"imageSendTime","type":"get","values":${t}}"""
}
}
}
"zeroCount" ->{
when (command.type) {
"set" -> {
val imageSendTime=command.values.jsonPrimitive.int
val mSet=deflectometer.updateZeroCount(imageSendTime)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"zeroCount","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readZeroCount()
reply = """{"command":"zeroCount","type":"get","values":${t}}"""
}
}
}
"resultCount" ->{
when (command.type) {
"set" -> {
val resultCount=command.values.jsonPrimitive.int
val mSet=deflectometer.updateResultCount(resultCount)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"resultCount","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readResultCount()
reply = """{"command":"resultCount","type":"get","values":${t}}"""
}
}
}
"dataFps" ->{
when (command.type) {
"set" -> {
val dataFps=command.values.jsonPrimitive.int
val mSet=deflectometer.updateDataFps(dataFps)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"dataFps","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readDataFps()
reply = """{"command":"dataFps","type":"get","values":${t}}"""
}
}
}
"videoFps" ->{
when (command.type) {
"set" -> {
val videoFps=command.values.jsonPrimitive.int
val mSet=deflectometer.updateVideoFps(videoFps)
val mSetStr=json.encodeToString<ManSetting2>(mSet)
fileUtils.saveFile(ctx,"settings.json",mSetStr)
reply = """{"command":"videoFps","type":"set","values":"ok"}"""
}
"get" -> {
val t=deflectometer.readVideoFps()
reply = """{"command":"videoFps","type":"get","values":${t}}"""
}
}
}
"name" ->{
when (command.type) {
"get" -> {
val ip= getIP4Address()
reply = """{"command":"name","type":"reply","values":"$ip"}"""
}
}
}
}
return reply
}
fun testParseValue(cmdStr:String){
val command = json.decodeFromString<Command>(cmdStr)
// 检查values字段的类型并处理
when (command.values) {
is JsonArray -> {
// 处理数组
command.values.jsonArray.forEach { element ->
val pointsStr=element.toString()
println(pointsStr)
}
}
is JsonObject -> {
// 处理对象
command.values.jsonObject.keys.forEach { key ->
println("Key: $key, Value: ${command.values.jsonObject[key]}")
}
}
is JsonNull -> {
println("null")
}
else ->{
println("其他类型")
}
}
}

43
MyOpenCv/app/src/main/java/com/example/myopencv/fileUtils.kt

@ -0,0 +1,43 @@
package com.example.myopencv
import android.content.Context
import android.util.Log
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
object fileUtils {
/*保存文件*/
fun saveFile(context: Context, fileName: String, cont: String) {
try {
//第一个参数是文件名
//第二个参数是文件的操作模式(相同文件MODE_PRIVATE覆盖,MODE_APPEND追加内容)
val output = context.openFileOutput(fileName, Context.MODE_PRIVATE)
val writer = BufferedWriter(OutputStreamWriter(output))
writer.use {
it.write(cont)
}
} catch (e: Exception) {
Log.e("配置settings.json", "存储异常 ${e.message}")
}
}
/*读取文件*/
fun readerFile(context: Context, fileName: String): String {
val content = StringBuffer()
try {
val input = context.openFileInput(fileName)
val reader = BufferedReader(InputStreamReader(input))
reader.use {
reader.forEachLine {
content.append(it)
}
}
} catch (e: Exception) {
Log.i("配置settings.json", "读取异常 ${e.message}")
}
return content.toString()
}
}

19
MyOpenCv/app/src/main/java/com/example/myopencv/models/centroidData.kt

@ -0,0 +1,19 @@
package com.example.myopencv.models
import kotlinx.serialization.Serializable
@Serializable
data class CentroidPoint(
val x: Double,
val y: Double
)
@Serializable
data class CentroidData(
val timestampStr: String,
val centroids: MutableList<CentroidPoint>
)

15
MyOpenCv/app/src/main/java/com/example/myopencv/models/command.kt

@ -0,0 +1,15 @@
package com.example.myopencv.models
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
@Serializable
data class Command(
val command: String,
val type: String,
val values: JsonElement= Json.parseToJsonElement("0")
)

39
MyOpenCv/app/src/main/java/com/example/myopencv/models/mSetting.kt

@ -0,0 +1,39 @@
package com.example.myopencv.models
import kotlinx.serialization.Serializable
@Serializable
data class ManSetting (
var dataFPS: Int=1,
var imageSendEnabled: Boolean=false,
var imageSendTime: Int=1000,
var invalidDataCount: Int=1,
var isClearZero: Boolean=false,
var resultCount: Int=10,
var sensors: MutableList<Sensor> =mutableListOf(),
var threshold: Int=128,
var videoFPS: Int=10,
var watchValues: String="pos, des, arg, tar, xReal, yReal",
var zeroCount: Int=30
)
@Serializable
data class ManSetting2 (
var baseParam:BaseParam=BaseParam(),
var sensors: MutableList<Sensor> =mutableListOf()
)
@Serializable
data class BaseParam (
var dataFPS: Int=1,
var imageSendEnabled: Boolean=false,
var imageSendTime: Int=1000,
var invalidDataCount: Int=1,
var isClearZero: Boolean=false,
var resultCount: Int=10,
var threshold: Int=128,
var videoFPS: Int=10,
var zeroCount: Int=1,
private var watchValues: String="pos, des, arg, tar, xReal, yReal",
)

17
MyOpenCv/app/src/main/java/com/example/myopencv/models/sensor.kt

@ -0,0 +1,17 @@
package com.example.myopencv.models
import kotlinx.serialization.Serializable
@Serializable
data class Sensor (
var arg: String,
var des: String,
var pos: String,
var tar: String,
var x: String,
var y: String,
var h: String,
var w: String,
var xZero: Double = 0.0,
var yZero: Double = 0.0,
)

19
MyOpenCv/app/src/main/java/com/example/myopencv/models/sensorData.kt

@ -0,0 +1,19 @@
package com.example.myopencv.models
import kotlinx.serialization.Serializable
@Serializable
data class SensorData(
var xCur: Double = 0.0,
var yCur: Double = 0.0,
var xAvg: Double = 0.0,
var yAvg: Double = 0.0,
var xZero: Double = 0.0,
var yZero: Double = 0.0,
var xTemp: Double = 0.0,
var yTemp: Double = 0.0,
var xReal: Double = Double.NaN,
var yReal: Double = Double.NaN,
var sensor: Sensor,
var invalidCount: Int = 0,
)

40
MyOpenCv/app/src/main/java/com/example/myopencv/models/uploadData.kt

@ -0,0 +1,40 @@
package com.example.myopencv.models
import kotlinx.serialization.Serializable
@Serializable
data class USensor (
var arg: String,
var des: String,
var pos: String,
var tar: String,
var xReal: Double?,
var yReal: Double?,
)
@Serializable
data class URealValue(
val sensors: MutableList<USensor>,
val timestamp: String
)
@Serializable
data class UData(
val command: String,
val type: String,
val values: URealValue
)
@Serializable
data class UImage(
val command: String,
val type: String,
val values: ImageInfo
)
@Serializable
data class ImageInfo(
val image: String,
val timestamp: String
)

12
MyOpenCv/app/src/main/java/com/example/myopencv/models/userInfo.kt

@ -0,0 +1,12 @@
package com.example.myopencv.models
import kotlinx.serialization.Serializable
@Serializable
data class UserInfo(
val id: Int,
var username: String,
var email: String,
var sex: String,
)

224
MyOpenCv/app/src/main/java/com/example/myopencv/tcpServer.kt

@ -0,0 +1,224 @@
package com.example.myopencv
import android.app.Service
import android.content.Intent
import android.graphics.Bitmap
import android.os.Binder
import android.os.IBinder
import android.util.Log
import com.example.myopencv.models.ImageInfo
import com.example.myopencv.models.UData
import com.example.myopencv.models.UImage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.io.PrintWriter
import java.net.NetworkInterface
import java.net.ServerSocket
import java.net.Socket
import java.util.regex.Pattern
import kotlin.math.log
class MyTcpServer:Service(){
private val coroutineScope = CoroutineScope(Dispatchers.IO)
// 内部Binder类
inner class LocalBinder : Binder() {
// 返回TcpService的实例
fun getService(): MyTcpServer = this@MyTcpServer
}
private val binder = LocalBinder()
override fun onBind(intent: Intent?): IBinder {
println("==onBind")
return binder
}
override fun onCreate() {
super.onCreate()
val ip= getIP4Address()
println(ip)
Thread(runnable).start()
dataTask()
imageTask()
heartTask()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("data","-> onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
serverAllowed = false
Log.d("data","-> onDestroy")
}
private var clientMaps= mutableMapOf<String,Socket>()
private var serverAllowed=true
private var runnable= kotlinx.coroutines.Runnable {
val serverSocket=ServerSocket(9999)
while (true) {
val accept: Socket = serverSocket.accept()
val acceptId=accept.remoteSocketAddress.toString()
clientMaps[acceptId] = accept
Thread { response(accept) }.start()
}
}
private fun response(accept: Socket) {
val acceptId=accept.remoteSocketAddress.toString()
//从客户端接收的信息
val bufferedReaderIn: BufferedReader = BufferedReader(InputStreamReader(accept.getInputStream()))
//发送信息给客户端
val out: PrintWriter = PrintWriter(BufferedWriter(OutputStreamWriter(accept.getOutputStream())),true)
try {
while (serverAllowed){
//0xOA换行为一次读取
val msg = bufferedReaderIn.readLine()
Log.i("tcp", "收到客户端[${accept.remoteSocketAddress}]的信息: $msg")
if (msg.length<=1){
continue
}
val reply = decodeCmd(msg,this)
if (reply.isNotEmpty()){
send2All(reply)
}
}
}catch (e:Exception){
println("异常:${e.message}")
println("异常-离线:$acceptId")
}finally {
println("关闭服务:$acceptId")
bufferedReaderIn.close()
out.close()
accept.close()
clientMaps.remove(acceptId)
println("剩余客户端数量:${clientMaps.size}")
}
}
private fun send2All(msg:String){
val nMsg=msg+"\n"
clientMaps.forEach{
try {
val out: PrintWriter = PrintWriter(
BufferedWriter(OutputStreamWriter(it.value.getOutputStream()))
,true)
out.println(nMsg);
}catch (e:Exception){
Log.i("数据上报","发送异常:${e.message}")
}
}
}
private fun sendData2All(r: MResult) {
//多次发送 更新时间戳
r.timestamp=timeNow2string()
val uploadData = result2uData(r)
if (uploadData.values.sensors.size==0){
return
}
val uploadDataJson = Json.encodeToString<UData>(uploadData)
send2All(uploadDataJson)
}
private fun sendImage2All(){
imageBitmapList.forEach {
val base64=bitmapToBase64(it)
val imgInfo= ImageInfo(base64,timeNow2string())
val uploadImage=UImage("image","reply",imgInfo)
val imageBase64= Json.encodeToString<UImage>(uploadImage)
send2All(imageBase64)
}
}
//缓存图像
private var imageBitmapList= mutableListOf<Bitmap>()
fun cacheImage(bitmap: Bitmap) {
if (imageBitmapList.size>0){
imageBitmapList[0]=bitmap
}else{
imageBitmapList.add(bitmap)
}
}
private fun imageTask(){
coroutineScope.launch {
while (true) {
delay(deflectometer.readImageSendTime().toLong())
if(deflectometer.imageSendEnabled) {
sendImage2All()
}
}
}
}
private fun dataTask(){
coroutineScope.launch {
while (true) {
val interval=deflectometer.readDataFps().toLong()
delay(1000/interval)
sendData2All(deflectometer.readResult())
}
}
}
private fun heartTask(){
coroutineScope.launch {
while (true) {
delay(10000L)
val heart="""{"command":"heartbeat","type":"reply","values":0}"""
send2All(heart)
}
}
}
}
fun getIP4Address(): String? {
try {
val en = NetworkInterface.getNetworkInterfaces()
while (en.hasMoreElements()) {
val intf = en.nextElement()
val enumIpAddr = intf.inetAddresses
while (enumIpAddr.hasMoreElements()) {
val inetAddress = enumIpAddr.nextElement()
if (!inetAddress.isLoopbackAddress && isIPv4(inetAddress.hostAddress)) {
return inetAddress.hostAddress
}
}
}
} catch (ex: java.net.SocketException) {
ex.printStackTrace()
}
return null
}
fun isIPv4(ip: String?): Boolean {
val pattern = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)$")
return pattern.matcher(ip?:"").matches()
}
val json = Json { ignoreUnknownKeys = true } // 允许JSON中存在未知键

11
MyOpenCv/app/src/main/java/com/example/myopencv/ui/theme/Color.kt

@ -0,0 +1,11 @@
package com.example.myopencv.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

58
MyOpenCv/app/src/main/java/com/example/myopencv/ui/theme/Theme.kt

@ -0,0 +1,58 @@
package com.example.myopencv.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun MyOpenCvTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}

34
MyOpenCv/app/src/main/java/com/example/myopencv/ui/theme/Type.kt

@ -0,0 +1,34 @@
package com.example.myopencv.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)

181
MyOpenCv/app/src/main/java/imageHandler.kt

@ -0,0 +1,181 @@
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Matrix
import androidx.camera.core.ImageProxy
import com.example.myopencv.imageHandler
import com.example.myopencv.models.CentroidPoint
import org.opencv.android.Utils
import org.opencv.core.CvType
import org.opencv.core.Mat
import org.opencv.core.Point
import org.opencv.core.Rect
import org.opencv.core.Scalar
import org.opencv.imgproc.Imgproc
class ImageHandler {
fun mat2bitMap(mat: Mat): Bitmap {
val bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.RGB_565)
Utils.matToBitmap(mat, bitmap)
return bitmap
}
fun mat2gary(mat: Mat): Mat {
//灰度
val garyMat = Mat(mat.width(), mat.height(), CvType.CV_8UC3)
Imgproc.cvtColor(mat, garyMat, Imgproc.COLOR_RGB2GRAY)
return garyMat
}
//图片二值化
fun binaryMat(thresholdValue: Double, mat: Mat): Mat {
// 设置二值化的最大值
val maxValue = 255.0
val binaryMat = Mat(mat.width(), mat.height(), CvType.CV_8UC3)
// 进行二值化操作
Imgproc.threshold(mat, binaryMat, thresholdValue, maxValue, Imgproc.THRESH_BINARY)
return binaryMat
}
fun binaryBitMap(thresholdValue: Double, mat: Mat): Bitmap {
// 设置二值化的最大值
val binaryMat = binaryMat(thresholdValue, mat)
val bitmap = mat2bitMap(binaryMat)
return bitmap
}
//图片加文字
fun tagText2mat(content: String, mat: Mat): Bitmap {
val point1 = Point(100.0, 100.0)
val point2 = Point(300.0, 300.0)
val color = Scalar(0.0, 0.0, 255.0)
Imgproc.line(mat, point1, point2, color, 5)
Imgproc.putText(mat, content, point1, 1, 10.0, color, 5)
val bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.RGB_565)
Utils.matToBitmap(mat, bitmap)
return bitmap
}
//裁剪图片指定区域
fun cropMat(mat: Mat,x: Int, y: Int, width: Int, height: Int): Mat {
val subMat: Mat = Mat(mat, Rect(x, y, width, height))
return subMat
}
//裁剪图片指定区域 并生成点位图
fun cropMat2bitMap(x: Int, y: Int, width: Int, height: Int, mat: Mat): Bitmap {
val subMat: Mat = Mat(mat, Rect(x, y, width, height))
val bitmap = Bitmap.createBitmap(subMat.width(), subMat.height(), Bitmap.Config.RGB_565)
Utils.matToBitmap(subMat, bitmap)
return bitmap
}
//计算质量心
fun calcMoments(binary: Mat): Point {
var center = Point(0.0, 0.0)
val moments = Imgproc.moments(binary)
val area = moments.m00
// 如果面积为0,则质心不存在
if (area != 0.0) {
val cx = moments.m10 / area
val cy = moments.m01 / area
center = Point(cx.toDouble(), cy.toDouble())
//println("质心: (${center.x}, ${center.y})")
} else {
println("质心不存在")
}
return center
}
fun rotateBitmap(original: Bitmap, degrees: Float): Bitmap {
// 创建一个新的Bitmap对象,具有与原始Bitmap相同的配置
val rotated = Bitmap.createBitmap(
original, 0, 0, original.width, original.height, null, false
)
// 创建Matrix对象
val matrix = Matrix()
// 设置旋转角度和旋转中心
matrix.postRotate(degrees, (original.width/2).toFloat(), (original.height/2).toFloat())
// 创建一个新的Canvas对象,并使用Matrix进行变换
val canvas = android.graphics.Canvas(rotated)
canvas.drawBitmap(original, matrix, null)
// 返回旋转后的Bitmap
return rotated
}
fun img2Moments(image: ImageProxy,threshold: Int,x: Int,y: Int,w: Int,h: Int):CentroidPoint{
val bitImg=image.toBitmap()
val rawMat=Mat(bitImg.width, bitImg.height, CvType.CV_8UC3)
Utils.bitmapToMat(bitImg,rawMat)
val subMat= imageHandler.cropMat(rawMat,x,y,w,h)
//灰度
val garyMat =imageHandler.mat2gary(subMat)
//二值化
val binaryMat=imageHandler.binaryMat(threshold.toDouble(),garyMat)
val center=imageHandler.calcMoments(binaryMat)
return CentroidPoint(center.x,center.y)
}
fun bitMap2Gray(bitImg: Bitmap):Bitmap{
val rawMat=Mat(bitImg.width, bitImg.height, CvType.CV_8UC3)
Utils.bitmapToMat(bitImg,rawMat)
//灰度
val garyMat =imageHandler.mat2gary(rawMat)
Utils.matToBitmap(garyMat,bitImg)
return bitImg
}
//外包的计算方法
fun getBinImageCentroid(image: Bitmap, threshold: Int, viewport: android.graphics.Rect): CentroidPoint {
val rect = android.graphics.Rect(0, 0, image.width, image.height)
val left = Math.max(viewport.left, rect.left)
val right = Math.min(viewport.right, rect.right)
val top = Math.max(viewport.top, rect.top)
val bottom = Math.min(viewport.bottom, rect.bottom)
var sumA = 0L
var sumX = 0L
var sumY = 0L
for (y in top until bottom) {
for (x in left until right) {
val pixel = image.getPixel(x, y)
val r = Color.red(pixel)
val g = Color.green(pixel)
val b = Color.blue(pixel)
val gary = qGary(r, g, b)
if (gary >= threshold) {
val v=255
sumA += v
sumX += v * (x - left)
sumY += v * (y - top)
}
}
}
val cp = if (sumA == 0L)
CentroidPoint(0.0,0.0)
else {
CentroidPoint(-1.0 * sumX / sumA, 1.0 * sumY / sumA)
}
return cp
}
fun qGary(r :Int,g :Int ,b :Int):Int{
return (r*11+g*16+b*5)/32
}
}

170
MyOpenCv/app/src/main/res/drawable/ic_launcher_background.xml

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

30
MyOpenCv/app/src/main/res/drawable/ic_launcher_foreground.xml

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

BIN
MyOpenCv/app/src/main/res/drawable/xml_4.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
MyOpenCv/app/src/main/res/drawable/yu_5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

BIN
MyOpenCv/app/src/main/res/drawable/zp_1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

6
MyOpenCv/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

6
MyOpenCv/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

BIN
MyOpenCv/app/src/main/res/mipmap-hdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-mdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

BIN
MyOpenCv/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-xhdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
MyOpenCv/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

10
MyOpenCv/app/src/main/res/values/colors.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

4
MyOpenCv/app/src/main/res/values/strings.xml

@ -0,0 +1,4 @@
<resources>
<string name="app_name">MyOpenCv</string>
<string name="centroid">raw centroid</string>
</resources>

5
MyOpenCv/app/src/main/res/values/themes.xml

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.MyOpenCv" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

13
MyOpenCv/app/src/main/res/xml/backup_rules.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

19
MyOpenCv/app/src/main/res/xml/data_extraction_rules.xml

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

137
MyOpenCv/app/src/main/res/图片.txt

File diff suppressed because one or more lines are too long

122
MyOpenCv/app/src/test/java/com/example/myopencv/ExampleUnitTest.kt

@ -0,0 +1,122 @@
package com.example.myopencv
import androidx.test.core.app.ActivityScenario.launch
import com.example.myopencv.models.CentroidData
import com.example.myopencv.models.CentroidPoint
import com.example.myopencv.models.Command
import com.example.myopencv.models.ManSetting
import com.example.myopencv.models.Sensor
import com.example.myopencv.models.SensorData
import kotlinx.coroutines.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
//@Test
// fun calc_CentroidPoint() {
// val cp2 = CentroidPoint(-284.11025502125176, 210.8166722226852)
// val centroidDataArray2 = CentroidData("", mutableListOf(cp2))
// val deflectometer = Deflectometer()
// deflectometer.updateSensor( mutableListOf(
// Sensor(
// arg = "0.448",
// des = "",
// pos = "1",
// tar = "n",
// x = "97",
// y = "1054",
// h = "425",
// w = "569",
// xZero = 0.0,
// yZero = 0.0
// )
// )
// )
// deflectometer.readSensor().forEach {
// val sd = SensorData(sensor = it)
// deflectometer.m_result.sensorsData.add(sd)
// }
//
// //设置上次数据的avg
// deflectometer.m_result.sensorsData[0].xAvg=-284.03910070884103
// deflectometer.m_result.sensorsData[0].yAvg= 210.88589473100282
//
// val r2 = deflectometer.dataProcess(centroidDataArray2)
// assertEquals(r2.sensorsData[0].yReal,94.4458,0.0001)
// assertEquals(r2.sensorsData[0].xReal,-127.2813,0.0001)
// }
@Test
fun parseCommand(){
val json = Json { ignoreUnknownKeys = true } // 允许JSON中存在未知键
//报文处理
val payLoad="""{"command":"sensors","type":"set","values":[{"arg":"0.448","des":"","h":"425","pos":"1","tar":"n","w":"569","x":"97","y":"1054"}]}
"""
//val payLoad2="""{"command":"sensors","type":"set","values":0} """
// decodeCmd(payLoad)
}
@Test
fun testLaunch(){
println("开始")
val r= runAsync()
println("结束")
Thread.sleep(2000) // 让当前线程暂停2秒
}
private fun run() {
val result= runBlocking {
val lr=launch {
doWorld()
println("Hello")
"123"
}
println("lr=${lr}")
"234"
}
println("r=${result}")
}
private fun runAsync() {
val result=runBlocking {
val lr=async {
doWorld()
"123"
}
delay(1100L)
println("Hello")
println("lr=${lr.await()}")
"234"
}
println("r=${result}")
}
private suspend fun doWorld(){
delay(1000L)
println("world")
}
}

5
MyOpenCv/build.gradle.kts

@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
}

23
MyOpenCv/gradle.properties

@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

40
MyOpenCv/gradle/libs.versions.toml

@ -0,0 +1,40 @@
[versions]
agp = "8.6.0"
cameraCoreVersion = "1.3.1"
kotlin = "1.9.0"
coreKtx = "1.10.1"
junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
kotlinxSerializationJson = "1.6.3"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0"
composeBom = "2024.04.01"
coreKtxVersion = "1.6.1"
[libraries]
androidx-camera-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraCoreVersion" }
androidx-camera-camera-camera22 = { module = "androidx.camera:camera-camera2", version.ref = "cameraCoreVersion" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
camera-core = { module = "androidx.camera:camera-core", version.ref = "cameraCoreVersion" }
camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "cameraCoreVersion" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "coreKtxVersion" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

6
MyOpenCv/gradle/wrapper/gradle-wrapper.properties

@ -0,0 +1,6 @@
#Sat Nov 16 20:08:14 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
MyOpenCv/gradlew

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
MyOpenCv/gradlew.bat

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

193
MyOpenCv/opencv/build.gradle

@ -0,0 +1,193 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Notes about integration OpenCV into existed Android Studio application project are below (application 'app' module should exist).
//
// This file is located in <OpenCV-android-sdk>/sdk directory (near 'etc', 'java', 'native' subdirectories)
//
// Add module into Android Studio application project:
//
// - Android Studio way:
// (will copy almost all OpenCV Android SDK into your project, ~200Mb)
//
// Import module: Menu -> "File" -> "New" -> "Module" -> "Import Gradle project":
// Source directory: select this "sdk" directory
// Module name: ":opencv"
//
// - or attach library module from OpenCV Android SDK
// (without copying into application project directory, allow to share the same module between projects)
//
// Edit "settings.gradle" and add these lines:
//
// def opencvsdk='<path_to_opencv_android_sdk_rootdir>'
// // You can put declaration above into gradle.properties file instead (including file in HOME directory),
// // but without 'def' and apostrophe symbols ('): opencvsdk=<path_to_opencv_android_sdk_rootdir>
// include ':opencv'
// project(':opencv').projectDir = new File(opencvsdk + '/sdk')
//
//
//
// Add dependency into application module:
//
// - Android Studio way:
// "Open Module Settings" (F4) -> "Dependencies" tab
//
// - or add "project(':opencv')" dependency into app/build.gradle:
//
// dependencies {
// implementation fileTree(dir: 'libs', include: ['*.jar'])
// ...
// implementation project(':opencv')
// }
//
//
//
// Load OpenCV native library before using:
//
// - avoid using of "OpenCVLoader.initAsync()" approach - it is deprecated
// It may load library with different version (from OpenCV Android Manager, which is installed separatelly on device)
//
// - use "System.loadLibrary("opencv_java4")" or "OpenCVLoader.initDebug()"
// TODO: Add accurate API to load OpenCV native library
//
//
//
// Native C++ support (necessary to use OpenCV in native code of application only):
//
// - Use find_package() in app/CMakeLists.txt:
//
// find_package(OpenCV 4.10 REQUIRED java)
// ...
// target_link_libraries(native-lib ${OpenCV_LIBRARIES})
//
// - Add "OpenCV_DIR" and enable C++ exceptions/RTTI support via app/build.gradle
// Documentation about CMake options: https://developer.android.com/ndk/guides/cmake.html
//
// defaultConfig {
// ...
// externalNativeBuild {
// cmake {
// cppFlags "-std=c++11 -frtti -fexceptions"
// arguments "-DOpenCV_DIR=" + opencvsdk + "/sdk/native/jni" // , "-DANDROID_ARM_NEON=TRUE"
// }
// }
// }
//
// - (optional) Limit/filter ABIs to build ('android' scope of 'app/build.gradle'):
// Useful information: https://developer.android.com/studio/build/gradle-tips.html (Configure separate APKs per ABI)
//
// splits {
// abi {
// enable true
// universalApk false
// reset()
// include 'armeabi-v7a' // , 'x86', 'x86_64', 'arm64-v8a'
// }
// }
//
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'kotlin-android'
def openCVersionName = "4.10.0"
def openCVersionCode = ((4 * 100 + 10) * 100 + 0) * 10 + 0
println "OpenCV: " +openCVersionName + " " + project.buildscript.sourceFile
android {
namespace 'org.opencv'
compileSdkVersion 31
defaultConfig {
minSdkVersion 21
targetSdkVersion 31
versionCode openCVersionCode
versionName openCVersionName
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
targets "opencv_jni_shared"
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
buildTypes {
debug {
packagingOptions {
doNotStrip '**/*.so' // controlled by OpenCV CMake scripts
}
}
release {
packagingOptions {
doNotStrip '**/*.so' // controlled by OpenCV CMake scripts
}
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
buildFeatures {
prefabPublishing true
buildConfig true
}
prefab {
opencv_jni_shared {
headers "native/jni/include"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['native/libs']
java.srcDirs = ['java/src']
res.srcDirs = ['java/res']
manifest.srcFile 'java/AndroidManifest.xml'
}
}
publishing {
singleVariant('release') {
withSourcesJar()
withJavadocJar()
}
}
externalNativeBuild {
cmake {
path (project.projectDir.toString() + '/libcxx_helper/CMakeLists.txt')
}
}
}
publishing {
publications {
release(MavenPublication) {
groupId = 'org.opencv'
artifactId = 'opencv'
version = '4.10.0'
afterEvaluate {
from components.release
}
}
}
repositories {
maven {
name = 'myrepo'
url = "${project.buildDir}/repo"
}
}
}
dependencies {
}

24
MyOpenCv/settings.gradle

@ -0,0 +1,24 @@
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "MyOpenCv"
include(":app")
include(":opencv")
Loading…
Cancel
Save