add open source traffic sign, vehicle and shape-color detector

master
UnknownObject 2 years ago
parent 95046e2198
commit dd8000a498

@ -49,10 +49,14 @@ dependencies {
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.rmtheis:tess-two:9.1.0'
implementation files('libs/camerautil.jar')
implementation project(path: ':opencv')
implementation files('libs/zxingcpp-release.aar')
implementation files('libs/Yolov5-tflite-Detector.aar')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//使
implementation 'org.tensorflow:tensorflow-lite:2.4.0'
implementation 'org.tensorflow:tensorflow-lite-gpu:2.4.0'
implementation 'com.google.code.gson:gson:2.10.1'
}

Binary file not shown.

@ -18,7 +18,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@ -37,7 +36,8 @@
android:supportsRtl="true"
android:theme="@style/Theme.MainCar"
android:usesCleartextTraffic="true"
tools:targetApi="31">
tools:targetApi="31"
tools:replace="android:label">
<activity
android:name=".gui.RaceTasks"
android:exported="false" />

@ -0,0 +1,6 @@
go_straight
no_turn
turn_around
turn_left
turn_right
no_straight

@ -0,0 +1,6 @@
bike
motor
car
truck
van
bus

@ -15,5 +15,6 @@ public enum GlobalColor
PURPLE,
CYAN,
BLACK,
WHITE
WHITE,
INVALIDATE
}

@ -12,5 +12,6 @@ public enum GlobalShape
CIRCLE,
SQUARE,
TRIANGLE,
RECTANGLE
RECTANGLE,
INVALIDATE
}

@ -0,0 +1,105 @@
/*
* Copyright (c) 2023. UnknownNetworkService Group
* This file is created by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.data_type;
import androidx.annotation.NonNull;
import com.uns.maincar.constants.GlobalColor;
import com.uns.maincar.constants.GlobalShape;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
public class ShapeColorResult
{
private final HashMap<GlobalColor, HashMap<GlobalShape, Integer>> storage;
public ShapeColorResult()
{
storage = new HashMap<>();
storage.put(GlobalColor.RED, new HashMap<>());
storage.put(GlobalColor.GREEN, new HashMap<>());
storage.put(GlobalColor.BLUE, new HashMap<>());
storage.put(GlobalColor.YELLOW, new HashMap<>());
storage.put(GlobalColor.PURPLE, new HashMap<>());
storage.put(GlobalColor.CYAN, new HashMap<>());
storage.forEach((k, v) ->
{
v.put(GlobalShape.STAR, 0);
v.put(GlobalShape.CIRCLE, 0);
v.put(GlobalShape.SQUARE, 0);
v.put(GlobalShape.TRIANGLE, 0);
v.put(GlobalShape.RECTANGLE, 0);
});
}
public void SetValue(GlobalColor color, GlobalShape shape, int value)
{
try
{
if (storage.containsKey(color) && Objects.requireNonNull(storage.get(color)).containsKey(shape))
Objects.requireNonNull(storage.get(color)).replace(shape, value);
}
catch (Exception ignored)
{
}
}
public int GetValue(GlobalColor color, GlobalShape shape)
{
try
{
if (storage.containsKey(color) && Objects.requireNonNull(storage.get(color)).containsKey(shape))
return Objects.requireNonNull(Objects.requireNonNull(storage.get(color)).get(shape));
else
return -1;
}
catch (Exception e)
{
return -2;
}
}
public int AllItemCount()
{
AtomicInteger sum = new AtomicInteger();
storage.forEach((k, v) -> v.forEach((s_k, s_v) -> sum.addAndGet(s_v)));
return sum.get();
}
public void Clear()
{
storage.clear();
storage.put(GlobalColor.RED, new HashMap<>());
storage.put(GlobalColor.GREEN, new HashMap<>());
storage.put(GlobalColor.BLUE, new HashMap<>());
storage.put(GlobalColor.YELLOW, new HashMap<>());
storage.put(GlobalColor.PURPLE, new HashMap<>());
storage.put(GlobalColor.CYAN, new HashMap<>());
storage.forEach((k, v) ->
{
v.put(GlobalShape.STAR, 0);
v.put(GlobalShape.CIRCLE, 0);
v.put(GlobalShape.SQUARE, 0);
v.put(GlobalShape.TRIANGLE, 0);
v.put(GlobalShape.RECTANGLE, 0);
});
}
@NonNull
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("--------------------ShapeColorResult START--------------------\n");
sb.append("Total Item Count: ").append(AllItemCount()).append("\n");
storage.forEach((k, v) -> v.forEach((s_k, s_v) -> sb.append("storage[").append(k).append("][").append(s_k).append("] = ").append(s_v).append("\n")));
sb.append("---------------------ShapeColorResult END---------------------\n");
return sb.toString();
}
}

@ -45,6 +45,10 @@ import com.uns.maincar.cpp_interface.QRDecoder;
import com.uns.maincar.cpp_interface.ShapeColor;
import com.uns.maincar.cpp_interface.TrafficLight;
import com.uns.maincar.cpp_interface.TrafficSign;
import com.uns.maincar.data_type.ShapeColorResult;
import com.uns.maincar.open_source.shape.ShapeDetector;
import com.uns.maincar.open_source.traffic_sign.YoloV5_tfLite_TSDetector;
import com.uns.maincar.open_source.vehicle.YoloV5_tfLite_VIDDetector;
import com.uns.maincar.tools.ImageReleaser;
import com.uns.maincar.tools.OCRDataReleaser;
import com.uns.maincar.tools.TextFilter;
@ -87,6 +91,10 @@ public class MainActivity extends AppCompatActivity
private final String SerialPortPath = "/dev/ttyS4";
//通信通道标志true为Wififalse为串口
private final boolean CommunicationUsingWifi = true;
//Yolo_tfLite检测模型对象 - 交通标志 - 来自开源项目
private static final YoloV5_tfLite_TSDetector TS_Detector = new YoloV5_tfLite_TSDetector();
//Yolo_tfLite检测模型对象 - 车型 - 来自于开源项目
private static final YoloV5_tfLite_VIDDetector VID_Detector = new YoloV5_tfLite_VIDDetector();
//调试用16进制数组
private final String[] byte_str = {
"0x00", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F",
@ -614,6 +622,26 @@ public class MainActivity extends AppCompatActivity
dtc_client.CloseConnection(); //关闭通信
throw new NullPointerException(); //通过异常来崩溃。
});
context.findViewById(R.id.btn_os_shapecolor).setOnClickListener(view ->
{
ShapeDetector detector = new ShapeDetector();
detector.shapePicProcess(currImage);
ShapeColorResult result = detector.GetAllResult();
ToastLog(result.toString(), false, false);
});
context.findViewById(R.id.btn_os_trafficsign).setOnClickListener(view ->
{
String res = TS_Detector.processImage(currImage);
ToastLog("Traffic Sign Result: " + res, false, false);
});
context.findViewById(R.id.btn_os_vehicle).setOnClickListener(view ->
{
String res = TS_Detector.processImage(currImage);
ToastLog("Vehicle Result: " + res, false, false);
});
}
//----------------------------------------到此处终止----------------------------------------
@ -747,6 +775,14 @@ public class MainActivity extends AppCompatActivity
//二维码扫描自检
ToastLog(QRDecoder.SelfTest(BitmapFactory.decodeResource(getResources(), R.drawable.qr_decode_test)), false, false);
//初始化开源交通标志识别库
YoloV5_tfLite_TSDetector.minimumConfidence = 0.7f;
ToastLog("Open Source Traffic Sign Detector: " + (TS_Detector.LoadModel("CPU", 4, this.getAssets()) ? "Success" : "Failure"), false, false);
//初始化开源车型识别库
YoloV5_tfLite_VIDDetector.minimumConfidence = 0.7f;
ToastLog("Open Source Vehicle Detector: " + (VID_Detector.LoadModel("CPU", 4, this.getAssets()) ? "Success" : "Failure"), false, false);
//获取主车IP地址
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
dhcpInfo = wifiManager.getDhcpInfo();

@ -0,0 +1,444 @@
/*
* Copyright (c) https://github.com/gh-xiao/EmbeddedCar
* This file is pull from GitHub open source project
* Integrated by UnknownObject at 2023 - 6 - 7
* Value/Result Interface changed by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.open_source.shape;
import android.graphics.Bitmap;
import android.util.Log;
import com.uns.maincar.constants.GlobalColor;
import com.uns.maincar.constants.GlobalShape;
import com.uns.maincar.data_type.ShapeColorResult;
import com.uns.maincar.open_source.utils.BitmapProcess;
import com.uns.maincar.open_source.utils.ColorHSV;
import com.uns.maincar.open_source.utils.ShapeStatistics;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ShapeDetector
{
//目标类的简写名称
private static final String TAG = ShapeDetector.class.getSimpleName();
//轮廓绘制/轮廓统计
private static final List<MatOfPoint> contours = new ArrayList<>();
//HashMap<颜色,HashMap<形状,数量>>
private final HashMap<String, ShapeStatistics> ColorCounts = new HashMap<>();
//检测出的所有图形数量
private int totals = 0;
//使用枚举类型的结果储存
ShapeColorResult result = new ShapeColorResult();
public int GetSpecItemCount(GlobalColor color, GlobalShape shape)
{
return result.GetValue(color, shape);
}
public int GetAllItemCount()
{
return result.AllItemCount();
}
public ShapeColorResult GetAllResult()
{
return result;
}
/**
*
*/
public int getTotals()
{
for (Map.Entry<String, ShapeStatistics> map : ColorCounts.entrySet())
{
totals += map.getValue().getCounts("总计");
}
return totals;
}
/**
*
*
* @param totals 0
*/
public void setTotals(int totals)
{
this.totals = totals;
}
/**
*
*
* @return <, >
*/
public HashMap<String, ShapeStatistics> getColorCounts()
{
return ColorCounts;
}
/**
*
*/
public int getShapeCounts(String shapeName)
{
int counts = 0;
for (Map.Entry<String, ShapeStatistics> map : ColorCounts.entrySet())
{
counts += map.getValue().getCounts(shapeName);
}
return counts;
}
/**
* - Bitmap
*
* @param inputBitmap
*/
public void shapePicProcess(Bitmap inputBitmap)
{
if (inputBitmap == null) return;
/* openCV创建用来存储图像信息的内存对象 */
Mat srcMat = new Mat();
/* 转化为Mat对象 */
Utils.bitmapToMat(inputBitmap, srcMat);
shapePicProcess(srcMat);
}
/**
* - Mat
*
* @param srcMat
*/
public void shapePicProcess(Mat srcMat)
{
if (srcMat == null)
return;
ColorCounts.clear();
/* 保存用 */
BitmapProcess.saveBitmap("TFTAutoCutter", srcMat);
/* 颜色形状分析 */
Identify(srcMat, ColorHSV.yellowHSV1, "黄色");
Identify(srcMat, ColorHSV.greenHSV1, "绿色");
Identify(srcMat, ColorHSV.cyanHSV, "青色");
Identify(srcMat, ColorHSV.blueHSV3, "蓝色");
Identify(srcMat, ColorHSV.purpleHSV2, "紫色");
/* 红色颜色取反,方便处理 */
Identify(srcMat, "红色");
}
/**
* <p> - </p>
* <p>,</p>
*
* @param inputMat Mat
*/
private void Identify(Mat inputMat, @SuppressWarnings("SameParameterValue") String colorName)
{
Mat dstMat = new Mat();
//RGB转换为BGR - 红蓝色互换
Imgproc.cvtColor(inputMat, dstMat, Imgproc.COLOR_BGR2RGB);
Identify(dstMat, ColorHSV.red2blueHSV, colorName);
}
/**
*
*
* @param Mtmp Mat
* @param r
* @param colorName
*/
private void Identify(Mat Mtmp, int[] r, String colorName)
{
/* openCV创建用来存储图像信息的内存对象 */
Mat hsvMat = new Mat();
Mat outMat = new Mat();
Mat mat = Mtmp.clone();
/* 转换为HSV */
Imgproc.cvtColor(mat, hsvMat, Imgproc.COLOR_RGB2HSV);
/* 颜色分割 */
Core.inRange(hsvMat, new Scalar(r[2], r[4], r[6]), new Scalar(r[1], r[3], r[5]), hsvMat);
/* 确定运算核,类似于卷积核 */
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
/* 开运算(除去白噪点) */
Imgproc.morphologyEx(hsvMat, hsvMat, Imgproc.MORPH_OPEN, kernel);
/* 闭运算(除去黑噪点) */
// Imgproc.morphologyEx(hsvMat, hsvMat, Imgproc.MORPH_CLOSE, kernel);
/* 轮廓提取,用于提取图像的轮廓 */
contours.clear();
Imgproc.findContours(hsvMat, contours, outMat, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
/* 绘制轮廓,用于绘制找到的图像轮廓 */
/*
* :
* image
* contoursvector
* contourIdx
* color
* thickness线CV_FILLED
*/
Imgproc.drawContours(mat, contours, -1, new Scalar(0, 255, 0), 2);
/* 形状统计 */
/* 核心统计代码,参数已调整 */
//轮廓
MatOfPoint2f contour2f;
//近似曲线(多边形拟合)
MatOfPoint2f approxCurve;
/* 逼近的精度(阈值),设定的原始曲线与近似曲线之间的最大距离 */
double epsilon;
int tri, rect, circle, star, rhombus;
tri = rect = circle = star = rhombus = 0;
Log.e(TAG, "----------" + colorName + "总计轮廓: " + contours.size() + "----------");
/* 遍历轮廓 */
for (int i = 0; i < contours.size(); i++)
{
/* 判断面积是否大于阈值(有效图形) */
if (Imgproc.contourArea(contours.get(i)) > 200)
{
Log.i(TAG, "查找到有效轮廓,面积为: " + Imgproc.contourArea(contours.get(i)));
/* 某一个点的集合(当前对象的轮廓) */
contour2f = new MatOfPoint2f(contours.get(i).toArray());
/*
*
* 0.035
*
* by New Bing
*/
epsilon = 0.045 * Imgproc.arcLength(contour2f, true);
//多边形拟合后的轮廓
approxCurve = new MatOfPoint2f();
/* 多边形拟合 */
Imgproc.approxPolyDP(contour2f, approxCurve, epsilon, true);
/* boundingRect获取不带旋转角度的最小外接矩形 */
// Rect minRect = Imgproc.boundingRect(approxCurve);
/* 绘制不带旋转角度的外接矩形,并计算外接矩形的轮廓中心 */
// Imgproc.rectangle(mat, minRect, new Scalar(255, 255, 0), 1);
/* minAreaRect获得带旋转角度的最小外接矩形 */
RotatedRect minRotatedRect = Imgproc.minAreaRect(approxCurve);
/* 获取顶点数据 */
Point[] box = new Point[4];
minRotatedRect.points(box);
/* 将顶点转换为整数类型 */
MatOfPoint boxInt = new MatOfPoint();
boxInt.fromArray(box);
/* 绘制带旋转角度的外接矩形,并计算外接矩形的轮廓中心 */
Imgproc.polylines(mat, Collections.singletonList(boxInt), true, new Scalar(255, 255, 255));
Log.i(TAG, "包含角点数: " + approxCurve.rows());
if (approxCurve.rows() == 3) tri++;
/* 判断矩形和菱形 */
/* 面积判断法 - 旧 */
// else if (approxCurve.rows() == 4) {
// double area, minArea;
// /* 该图形(四边形)拟合的面积 */
// area = Imgproc.contourArea(approxCurve);
// /* 包含旋转角度的最小外接矩形的面积 */
// RotatedRect minAreaRect = Imgproc.minAreaRect(approxCurve);
// minArea = minAreaRect.size.area();
// /* 图形面积/外接矩形面积 */
// double rec = area / minArea;
// Log.i(TAG, "这是area / minArea得到的阈值: " + rec);
// if (rec >= 0.80 && rec < 1.15) rect++;
// else rhombus++;
// }
/* 判断菱形 - 边长 */
else if (isRhombus(approxCurve)) rhombus++;
/* 判断矩形 - 对角线 */
else if (isRectangle(approxCurve)) rect++;
/* 判断五角星和圆形 - 面积 */
// else if (approxCurve.rows() > 4) {
// /* 最小外接矩形的面积 */
// int minAreaRect = minRect.height * minRect.width;
// /* 该图形面积 */
// double area = Imgproc.contourArea(contours.get(i));
// if ((area / minAreaRect) > 0.5) circle++;
// else star++;
// }
/* 判断五角星和圆形 - 圆形度 */
else if (approxCurve.rows() > 4)
{
/* 该图形面积 */
double area = Imgproc.contourArea(contours.get(i));
/* 该图形周长 */
double len = Imgproc.arcLength(approxCurve, true);
/* 圆形度 */
double roundness = (4 * Math.PI * area) / (len * len);
Log.i(TAG, "该图形的圆形度: " + roundness);
if (roundness > 0.8) circle++;
else star++;
}
}
}
/* 引用ShapeCount对象存放识别数据 */
//SaveResult(colorName, circle, tri, rect, star, rhombus);
//使用枚举类型的数据存储,这样更便于查询
BetterSaveResult(colorName, circle, tri, rect, star, rhombus);
/* 输出结果 */
String msg = "圆形: " + circle + " 三角形: " + tri + " 矩形: " + rect + " 菱形: " + rhombus + " 五角星: " + star;
Log.e(TAG, msg);
/* 保存图片 */
BitmapProcess.saveBitmap(colorName, mat);
Log.e(TAG, "----------" + colorName + "识别完成----------");
}
/**
*
*
* @param approxCurve MatOfPoint2f
* @return boolean
*/
private static boolean isRhombus(MatOfPoint2f approxCurve)
{
/* 如果顶点数为4则可能为菱形 */
if (approxCurve.toArray().length == 4)
{
/* 获取顶点坐标 */
Point[] points = approxCurve.toArray();
/* 获取边长长度 */
double l1 = getDistance(points[0], points[1]);
double l2 = getDistance(points[1], points[2]);
double l3 = getDistance(points[2], points[3]);
double l4 = getDistance(points[3], points[0]);
Log.i(TAG, "该轮廓四边边长(顺时针):\n" + "■■■" + l1 + "■■■" + l2 + "■■■\n■■■" + l4 + "■■■" + l3 + "■■■");
/* 轮廓的邻边边长在误差范围内相等则为菱形 */
return Math.abs(l1 - l2) < 5 && Math.abs(l2 - l3) < 5 && Math.abs(l3 - l4) < 5 && Math.abs(l4 - l1) < 5;
}
// 不是菱形
return false;
}
/**
*
*
* @param approxCurve MatOfPoint2f
* @return boolean
*/
private static boolean isRectangle(MatOfPoint2f approxCurve)
{
/* 如果顶点数为4则可能为矩形 */
if (approxCurve.toArray().length == 4)
{
/* 计算四个顶点之间的距离 */
// double d1 = getDistance(approxCurve.toArray()[0], approxCurve.toArray()[1]);
// double d2 = getDistance(approxCurve.toArray()[1], approxCurve.toArray()[2]);
// double d3 = getDistance(approxCurve.toArray()[2], approxCurve.toArray()[3]);
// double d4 = getDistance(approxCurve.toArray()[3], approxCurve.toArray()[0]);
/* 计算对角线之间的距离 */
double d5 = getDistance(approxCurve.toArray()[0], approxCurve.toArray()[2]);
double d6 = getDistance(approxCurve.toArray()[1], approxCurve.toArray()[3]);
/* 判断对角线是否相等,并且相邻边是否垂直(即乘积为零) */
// double vector = Math.abs(d1 * d2 + d2 * d3 + d3 * d4 + d4 * d1);
// Log.e(TAG, "对角线长度比对: " + Math.abs(d5 - d6) + "邻边角度误差: " + vector);
// return Math.abs(d5 - d6) < 1e-6 && vector < 1e-6; // 是矩形
/* 判断对角线是否相等 */
Log.e(TAG, "对角线长度比对: " + Math.abs(d5 - d6));
return Math.abs(d5 - d6) < 3; // 是矩形
}
// 不是矩形
return false;
}
/**
*
*
* @param p1 -
* @param p2 -
* @return
*/
private static double getDistance(Point p1, Point p2)
{
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
/**
*
*
* @param colorName
* @param circle -
* @param tri -
* @param rect -
* @param star -
* @param rhombus -
*/
/*private void SaveResult(String colorName, int circle, int tri, int rect, int star, int rhombus)
{
*//* 保存该颜色包含的图形统计 *//*
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("三角形", tri);
hashMap.put("矩形", rect);
hashMap.put("菱形", rhombus);
hashMap.put("五角星", star);
hashMap.put("圆形", circle);
hashMap.put("总计", tri + rect + rhombus + star + circle);
*//* 形状计数对象 *//*
ShapeStatistics statistics = new ShapeStatistics();
*//* 保存在该对象上 *//*
statistics.setShapeStatistics(hashMap);
ColorCounts.put(colorName, statistics);
}*/
/**
*
*
* @param color_name
*/
private GlobalColor ConvertColorName(String color_name)
{
switch (color_name)
{
case "红色":
return GlobalColor.RED;
case "黄色":
return GlobalColor.YELLOW;
case "绿色":
return GlobalColor.GREEN;
case "青色":
return GlobalColor.CYAN;
case "蓝色":
return GlobalColor.BLUE;
case "紫色":
return GlobalColor.PURPLE;
}
return GlobalColor.INVALIDATE;
}
/**
* 使
* 使Key UnknownObject@2023-06-07
*
* @param colorName
* @param circle
* @param tri
* @param rect
* @param star
* @param rhombus
*/
private void BetterSaveResult(String colorName, int circle, int tri, int rect, int star, int rhombus)
{
GlobalColor color = ConvertColorName(colorName);
if (color != GlobalColor.INVALIDATE)
{
result.SetValue(color, GlobalShape.CIRCLE, circle);
result.SetValue(color, GlobalShape.TRIANGLE, tri);
result.SetValue(color, GlobalShape.RECTANGLE, rect);
result.SetValue(color, GlobalShape.STAR, star);
result.SetValue(color, GlobalShape.SQUARE, rhombus);
}
}
}

@ -0,0 +1,190 @@
/*
* Copyright (c) https://github.com/gh-xiao/EmbeddedCar
* This file is pull from GitHub open source project
* Integrated by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.open_source.traffic_sign;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.SystemClock;
import android.util.Log;
import com.google.gson.Gson;
import com.uns.maincar.open_source.utils.BitmapProcess;
import org.tensorflow.lite.examples.detection.env.Logger;
import org.tensorflow.lite.examples.detection.tflite.Classifier;
import org.tensorflow.lite.examples.detection.tflite.DetectorFactory;
import org.tensorflow.lite.examples.detection.tflite.YoloV5Classifier;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* 使YoloV5-tfLite
*/
public class YoloV5_tfLite_TSDetector
{
// Which detection model to use: by default uses Tensorflow Object Detection API frozen
// checkpoints.
// enum DetectorMode {TF_OD_API}
//日志对象
private static final Logger LOGGER = new Logger();
//枚举常量 - 检测模式
// private static final DetectorMode MODE = DetectorMode.TF_OD_API;
public static final float MINIMUM_CONFIDENCE_TF_OD_API = 0.35f;
//最小置信度
public static float minimumConfidence;
//核心检测对象
private YoloV5Classifier detector;
//模型列表
private final String[] models = new String[]{"TSyolov5s-fp16.tflite", "TSyolov5s-fp16-3.tflite", "TSyolov5s-fp16-byGray.tflite"};
//检测图片
private Bitmap SaveBitmap;
private long timestamp = 0;
public Bitmap getSaveBitmap()
{
return SaveBitmap;
}
/**
*
*
* @param device 使
* @param numThreads 使线
* @param assetManager AssetManager
*/
public boolean LoadModel(String device, int numThreads, AssetManager assetManager)
{
//模型文件
String modelString = models[2];
//检测类别(标签)
String labelFilename = "TSclass.txt";
/* 线程数(不推荐超过9线程数) */
if (numThreads > 9) numThreads = 4;
LOGGER.i("Changing model to ***" + modelString + "*** device ***" + device + "***");
/* Try to load model. */
/* 尝试加载模型 */
try
{
detector = DetectorFactory.getDetector(assetManager, modelString, labelFilename);
// Customize the interpreter to the type of device we want to use.
}
catch (IOException e)
{
e.printStackTrace();
LOGGER.e(e, "Exception in updateActiveModel()");
// Toast toast = Toast.makeText(FirstActivity.getContext(), "Classifier could not be initialized", Toast.LENGTH_SHORT);
return false;
}
switch (device)
{
case "GPU":
detector.useGpu();
break;
case "NNAPI":
detector.useNNAPI();
break;
default:
detector.useCPU();
break;
}
/* 设置线程数 */
detector.setNumThreads(numThreads);
return true;
}
/**
*
*
* @param inputBitmap -
* @return Gson
*/
public String processImage(Bitmap inputBitmap)
{
/* 结果列表对象 */
List<Classifier.Recognition> recognitions = new LinkedList<>();
/* 将结果转换成Gson */
Gson gson = new Gson();
if (inputBitmap == null) return gson.toJson(recognitions);
//416*416
int cropSize = detector.getInputSize();
System.out.println(cropSize);
int width = inputBitmap.getWidth();
int height = inputBitmap.getHeight();
float scaleWidth = ((float) cropSize) / width;
float scaleHeight = ((float) cropSize) / height;
//矩阵
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
/* 将输入图片通过矩阵变换得到416*416大小的新图片 */
Bitmap croppedBitmap = Bitmap.createBitmap(inputBitmap, 0, 0, width, height, matrix, true);
/* 灰度化图像 */
croppedBitmap = BitmapProcess.GrayscaleImage(croppedBitmap);
/* 设置输出结果图像(在该图像上绘制识别结果) */
Bitmap draw = croppedBitmap.copy(Bitmap.Config.ARGB_8888, true);
++timestamp;
final long currTimestamp = timestamp;
LOGGER.i("Preparing image " + currTimestamp + " for detection in bg thread.");
/* 利用分类器classifier对图片进行预测分析得到图片为每个分类的概率. 比较耗时 */
LOGGER.i("Running detection on image " + currTimestamp);
final long startTime = SystemClock.uptimeMillis();
/* 核心检测 */
final List<Classifier.Recognition> results = detector.recognizeImage(croppedBitmap);
/* 计算检测时间 */
long lastProcessingTimeMs = SystemClock.uptimeMillis() - startTime;
/* 检测出多少对象 */
Log.e("CHECK", "run: " + results.size());
/* 检测时间 */
Log.i("Time Spent: ", lastProcessingTimeMs + "ms");
/* 筛选通过最低置信度阈值的识别结果 */
final List<Classifier.Recognition> mappedRecognitions = new LinkedList<>();
for (final Classifier.Recognition result : results)
{
final RectF location = result.getLocation();
if (location != null && result.getConfidence() >= minimumConfidence)
{
result.setLocation(location);
/* 将通过最低置信度的结果添加到新List */
mappedRecognitions.add(result);
//识别结果
Log.e("result: ", result.getTitle() + result.getConfidence());
drawBitmap(result, draw);
}
}
return gson.toJson(mappedRecognitions.size() > 0 ? mappedRecognitions : recognitions);
}
private void drawBitmap(Classifier.Recognition result, Bitmap resultBitmap)
{
final Canvas canvas = new Canvas(resultBitmap);
final Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2.0f);
canvas.drawRect(result.getLocation(), paint);
SaveBitmap = resultBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
}

@ -0,0 +1,308 @@
/*
* Copyright (c) https://github.com/gh-xiao/EmbeddedCar
* This file is pull from GitHub open source project
* Integrated by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.open_source.utils;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.util.Log;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class BitmapProcess
{
@SuppressLint("StaticFieldLeak")
private static BitmapProcess mInstance;
private Context mContext;
// 指定我们想要存储文件的地址
public static final String TargetPath = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/Tess/";
// 获取时间
private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA);
private BitmapProcess()
{
}
public static synchronized BitmapProcess getInstance()
{
if (mInstance == null)
{
mInstance = new BitmapProcess();
}
return mInstance;
}
public void init(Context context)
{
this.mContext = context.getApplicationContext();
}
/**
* 使
*
* @param name
* @param mat mat
*/
public static void saveBitmap(String name, Mat mat)
{
if (mat == null) return;
Bitmap bm = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat, bm);
saveBitmap(name, bm);
}
/**
* 使
*
* @param name
* @param bm Bitmap
* @return
*/
public static String saveBitmap(String name, Bitmap bm)
{
if (bm == null) return "错误,没有图片!";
return Build.VERSION.SDK_INT < 29 ? saveImageOld(name, bm) : mInstance.saveImageNew(name, bm);
}
/**
* Android
*
* @param name
* @param bm Bitmap
* @return
*/
private static String saveImageOld(String name, Bitmap bm)
{
Log.d("Save Bitmap", "Ready to save picture");
StringBuilder append = new StringBuilder().append("Save Path = ");
String str = TargetPath;
Log.d("Save Bitmap", append.append(str).toString());
if (fileIsExist())
{
try
{
FileOutputStream saveImgOut = new FileOutputStream(new File(str, name + "-" + format.format(new Date()) + ".jpg"));
bm.compress(Bitmap.CompressFormat.JPEG, 80, saveImgOut);
saveImgOut.flush();
Log.d("Save Bitmap", "The picture is save to your phone!");
return "保存完毕!";
}
catch (IOException ex)
{
ex.printStackTrace();
return "IOException!";
}
}
else
{
Log.d("Save Bitmap", "TargetPath isn't exist");
return "TargetPath isn't exist!";
}
}
static boolean fileIsExist()
{
File file = new File(TargetPath);
return file.exists() || file.mkdirs();
}
/**
* Android
*
* @param name
* @param bm Bitmap
* @return
*/
private String saveImageNew(String name, Bitmap bm)
{
ContentValues contentValues = new ContentValues();
contentValues.put("_display_name", name + format.format(new Date()));
contentValues.put("description", name);
contentValues.put("mime_type", "image/jpeg");
contentValues.put("relative_path", "DCIM/Tess");
try (OutputStream outputStream = mContext.getContentResolver()
.openOutputStream(mContext.getContentResolver()
.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)))
{
bm.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
Log.d("Save Bitmap", "Save success!");
return "保存完毕!";
}
catch (Exception e)
{
e.printStackTrace();
Log.d("Save Bitmap", "Save fail!");
return "Exception!";
}
}
/**
* URL
*
* @param uri -
* @return Bitmap
*/
public Bitmap showImage(Uri uri)
{
try (ParcelFileDescriptor parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(uri, "r"))
{
return BitmapFactory.decodeFileDescriptor(parcelFileDescriptor.getFileDescriptor());
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}
/**
* Tess
*
* @param imageName
* @return Bitmap
*/
public static Bitmap getImages(String imageName)
{
String path = TargetPath + imageName;
return new File(path).exists() ? BitmapFactory.decodeFile(path) : null;
}
/**
* Bitmap
*
* @param realPath
* @return Bitmap
*/
public static Bitmap getRealPathImages(String realPath)
{
return new File(realPath).exists() ? BitmapFactory.decodeFile(realPath) : null;
}
/**
*
*
* @param inputBitmap Bitmap
* @return Bitmap
*/
public static Bitmap GrayscaleImage(Bitmap inputBitmap)
{
if (inputBitmap == null) return null;
Mat mat = new Mat();
Utils.bitmapToMat(inputBitmap, mat);
return GrayscaleImage(mat);
}
/**
*
*
* @param colorImage Bitmap
* @return Bitmap
*/
public static Bitmap GrayscaleImage(Mat colorImage)
{
if (colorImage == null) return null;
// 创建一个空的灰度图像
Mat grayscaleImage = new Mat();
// 调用cvtColor函数将彩色图像转换为灰度图像
Imgproc.cvtColor(colorImage, grayscaleImage, Imgproc.COLOR_RGB2GRAY);
Bitmap result = Bitmap.createBitmap(colorImage.width(), colorImage.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(grayscaleImage, result);
return result;
}
/**
*
*/
private void GrayscaleImage()
{
// 定义源文件夹和目标文件夹的路径
String sourcePath = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/srcImg/";
String targetPath = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/dstImg/";
// 创建File对象表示源文件夹和目标文件夹
File sourceFolder = new File(sourcePath);
File targetFolder = new File(targetPath);
// 检查源文件夹是否存在,如果不存在,打印错误信息并退出
if (!sourceFolder.exists())
{
System.out.println("Source folder does not exist.");
return;
}
// 检查目标文件夹是否存在,如果不存在,就创建一个
if (!targetFolder.exists()) if (!targetFolder.mkdir()) return;
// 获取源文件夹中的所有文件存放在一个File数组中
File[] files = sourceFolder.listFiles();
if (files == null) return;
// 遍历File数组对每个文件进行灰度化处理
for (File file : files)
{
// 获取文件
Bitmap bitmap = BitmapProcess.getRealPathImages(sourcePath + file.getName());
if (bitmap == null) continue;
// 加载原始图像
Mat colorImage = new Mat();
Utils.bitmapToMat(bitmap, colorImage);
// 创建一个空的灰度图像
Mat grayscaleImage = new Mat();
// 调用cvtColor函数将彩色图像转换为灰度图像
Imgproc.cvtColor(colorImage, grayscaleImage, Imgproc.COLOR_RGB2GRAY);
Utils.matToBitmap(grayscaleImage, bitmap);
// 获取文件的名称,不包括扩展名
StringBuilder fileName = new StringBuilder();
for (int j = 0; j < file.getName().split("\\.").length - 1; j++)
{
fileName.append(file.getName().split("\\.")[j]).append(".");
}
Imgcodecs.imwrite(file.getName(), grayscaleImage);
if (file.getName().split("\\.")[file.getName().split("\\.").length - 1].equals("jpg"))
{
try
{
FileOutputStream saveImgOut = new FileOutputStream(new File(targetPath, fileName + "jpg"));
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, saveImgOut);
saveImgOut.flush();
Log.d("Save Bitmap", "The picture is save to your phone!");
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
else
{
try
{
FileOutputStream saveImgOut = new FileOutputStream(new File(targetPath, fileName + "png"));
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, saveImgOut);
saveImgOut.flush();
Log.d("Save Bitmap", "The picture is save to your phone!");
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
}

@ -0,0 +1,116 @@
/*
* Copyright (c) https://github.com/gh-xiao/EmbeddedCar
* This file is pull from GitHub open source project
* Integrated by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.open_source.utils;
/**
* <p>Hsv</p>
* <p>使HSVH()</p>
* <p>2,4,6,1,3,5</p>
* <p>HSV,,使</p>
*/
@SuppressWarnings("ALL")
public final class ColorHSV
{
/* 图形识别色彩数据 */
//所有H(色彩度)
public static final int[] allHSV = new int[]{0, 180, 0, 255, 150, 255, 110};
//红色:0-20
public static final int[] redDownHSV = new int[]{0, 25, 0, 255, 110, 255, 110};
public static final int[] redDownHSV1 = new int[]{0, 25, 0, 255, 150, 255, 110};
//红色:160-180
public static final int[] redUpHSV = new int[]{0, 180, 160, 255, 150, 255, 110};
public static final int[] redUpHSV1 = new int[]{0, 180, 150, 255, 110, 255, 110};
//黄色
public static final int[] yellowHSV = new int[]{0, 43, 25, 255, 150, 255, 110};
public static final int[] yellowHSV1 = new int[]{0, 43, 25, 255, 110, 255, 225};
//绿色
public static final int[] greenHSV = new int[]{0, 70, 55, 255, 150, 255, 110};
public static final int[] greenHSV1 = new int[]{0, 70, 40, 255, 150, 255, 110};
//青色
public static final int[] cyanHSV = new int[]{0, 95, 85, 255, 150, 255, 110};
public static final int[] cyanHSV1 = new int[]{0, 95, 85, 255, 190, 255, 110};
//蓝色
public static final int[] blueHSV = new int[]{0, 120, 110, 255, 150, 255, 110};
public static final int[] blueHSV1 = new int[]{0, 130, 95, 255, 225, 255, 110};
public static final int[] blueHSV2 = new int[]{0, 120, 85, 255, 210, 255, 195};
public static final int[] blueHSV3 = new int[]{0, 120, 85, 255, 210, 255, 110};
public static final int[] blueHSV4 = new int[]{0, 130, 110, 255, 210, 255, 195};
//蓝色 - 红色取反
public static final int[] red2blueHSV = new int[]{0, 140, 110, 255, 150, 255, 110};
//紫色
public static final int[] purpleHSV = new int[]{0, 160, 125, 255, 150, 255, 110};
public static final int[] purpleHSV1 = new int[]{0, 155, 125, 255, 150, 255, 110};
public static final int[] purpleHSV2 = new int[]{0, 155, 125, 255, 125, 255, 110};
public static final int[] purpleHSV3 = new int[]{0, 155, 125, 255, 125, 255, 200};
//实验性 - 白
public static final int[] whiteHSV = new int[]{0, 110, 0, 60, 0, 255, 225};
//实验性 - 黑
public static final int[] blackHSV = new int[]{0, 100, 47, 225, 50, 60, 0};
/* 车牌识别数据 */
//浅蓝0、//黄色1、//品红2、//浅红色3、//蓝色4、//青色5、// 深红色6、//黑色7 车牌蓝底9 车牌绿底10
public static double[][] PlateDetector_HSV_VALUE_LOW = {
{10, 163, 147}, //浅蓝0
{77, 163, 147}, //黄色1
{146, 212, 140},//品红2
{126, 155, 160},//浅红色3
{0, 204, 178}, //蓝色4
{35, 163, 147}, //青色5
{110, 155, 160},//深红色6
{0, 0, 0}, //黑色7
{0, 0, 192}, //标准蓝8
{0, 190, 190}, //车牌蓝底9 暗的TFT0,190,190 亮的0,180,190
{22, 195, 158}, //车牌绿底10 暗的TFT H:21 S要调高一点:210 V:211 亮的TFT S值要调底一点110 10,100,148
{65, 0, 200}, //新能源车牌白变绿渐变
};
public static double[][] PlateDetector_HSV_VALUE_HIGH = {
{47, 255, 255}, //浅蓝0
{111, 255, 255}, //黄色1
{241, 255, 255.0}, //品红2
{150, 255, 255}, //浅红色3
{21, 255, 255}, //蓝色4
{75, 255.0, 255}, //青色5
{150, 255, 255}, //深红色6
{180, 255, 120}, //黑色7
{45, 238, 255}, //标准蓝8
{28, 255, 255}, //车牌蓝底9 亮暗一样
{73, 255, 255}, //车牌绿底10 暗H:66 亮H:83
{110, 255, 255}, //新能源车牌白变绿渐变
};
//浅蓝0、//黄色1、//品红2、//浅红色3、//蓝色4、//青色5、// 深红色6、//黑色7
//暗 S、V=214,211 亮 S、V=176,160
//浅蓝0、//黄色1、//品红2、//浅红色3、//蓝色4、//青色5、// 深红色6、//黑色7 车牌蓝底9 车牌绿底10
public static double[][] HSV_VALUE_LOW = {
{13, 176, 160},//浅蓝0 12,214,211
{67, 176, 160},//黄色1
{130, 176, 160},//品红2 暗100, 176,160 亮130,176,160
{126, 176, 160},//浅红色3
{0, 176, 160},//蓝色4
{30, 176, 160},//青色5 35
{103, 176, 160},// 深红色6
{0, 0, 0},//黑色7 暗0,187,0 亮0,0,0
{0, 0, 192},//标准蓝8
{0, 150, 190},//车牌蓝底9 暗的TFT0,190,190 亮的0,180,190
{22, 104, 161},//车牌绿底10 暗的TFT H:21 S要调高一点:210 V:211 亮的TFT S值要调底一点110 10,100,148
};
public static double[][] HSV_VALUE_HIGH = {
{30, 255, 255},//浅蓝0
{111, 255, 255},//黄色1
{241, 255, 255.0},//品红2
{150, 255, 255},//浅红色3
{12, 255, 255},//蓝色4
{70, 255.0, 255},//青色5 90
{150, 255, 255},// 深红色6
{255, 255, 150},//黑色7 暗28,255,184 亮255,255,150
{45, 238, 255},//标准蓝8
{126, 255, 255},//车牌蓝底9 亮暗一样
{120, 255, 255},//车牌绿底10 暗H:66 亮H:83
};
}

@ -0,0 +1,40 @@
/*
* Copyright (c) https://github.com/gh-xiao/EmbeddedCar
* This file is pull from GitHub open source project
* Integrated by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.open_source.utils;
import java.util.HashMap;
/**
*
*/
public class ShapeStatistics
{
//统计形状数量
private HashMap<String, Integer> shapeStatistics = new HashMap<>();
/**
*
*
* @param shapeName /////
* @return
*/
public Integer getCounts(String shapeName)
{
return shapeStatistics.get(shapeName);
}
/**
*
*
* @param shapeStatistics HashMap
*/
public void setShapeStatistics(HashMap<String, Integer> shapeStatistics)
{
this.shapeStatistics = shapeStatistics;
}
}

@ -0,0 +1,195 @@
/*
* Copyright (c) https://github.com/gh-xiao/EmbeddedCar
* This file is pull from GitHub open source project
* Integrated by UnknownObject at 2023 - 6 - 7
*/
package com.uns.maincar.open_source.vehicle;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.SystemClock;
import android.util.Log;
import com.google.gson.Gson;
import org.tensorflow.lite.examples.detection.env.Logger;
import org.tensorflow.lite.examples.detection.tflite.Classifier;
import org.tensorflow.lite.examples.detection.tflite.DetectorFactory;
import org.tensorflow.lite.examples.detection.tflite.YoloV5Classifier;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* 使YoloV5-tfLite
*/
public class YoloV5_tfLite_VIDDetector
{
// Which detection model to use: by default uses Tensorflow Object Detection API frozen
// checkpoints.
// enum DetectorMode {TF_OD_API}
//日志对象
private static final Logger LOGGER = new Logger();
//枚举常量 - 检测模式
// private static final DetectorMode MODE = DetectorMode.TF_OD_API;
public static final float MINIMUM_CONFIDENCE_TF_OD_API = 0.3f;
//最小置信度
public static float minimumConfidence;
//核心检测对象
private YoloV5Classifier detector;
//模型列表
private final String[] models = new String[]{"VIDyolov5s-fp16.tflite", "VIDyolov5s-fp16-2.tflite"};
//检测图片
private Bitmap SaveBitmap;
private long timestamp = 0;
public Bitmap getSaveBitmap()
{
return SaveBitmap;
}
/**
*
*
* @param device 使
* @param numThreads 使线
* @param assetManager assetManager
*/
public boolean LoadModel(String device, int numThreads, AssetManager assetManager)
{
//模型文件
String modelString = models[0];
//检测类别(标签)
String labelFilename = "VIDclass.txt";
/* 线程数(不推荐超过9线程数) */
if (numThreads > 9) numThreads = 4;
LOGGER.i("Changing model to ***" + modelString + "*** device ***" + device + "***");
/* Try to load model. */
/* 尝试加载模型 */
try
{
detector = DetectorFactory.getDetector(assetManager, modelString, labelFilename);
// Customize the interpreter to the type of device we want to use.
}
catch (IOException e)
{
e.printStackTrace();
LOGGER.e(e, "Exception in updateActiveModel()");
// Toast toast = Toast.makeText(FirstActivity.getContext(), "Classifier could not be initialized", Toast.LENGTH_SHORT);
return false;
}
switch (device)
{
case "GPU":
detector.useGpu();
break;
case "NNAPI":
detector.useNNAPI();
break;
default:
detector.useCPU();
break;
}
/* 设置线程数 */
detector.setNumThreads(numThreads);
return true;
}
/**
*
*
* @param inputBitmap -
* @return
*/
public String processImage(Bitmap inputBitmap)
{
/* 结果列表对象 */
List<Classifier.Recognition> recognitions = new LinkedList<>();
/* 将结果转换成Gson */
Gson gson = new Gson();
if (inputBitmap == null) return gson.toJson(recognitions);
//416*416
int cropSize = detector.getInputSize();
System.out.println(cropSize);
int width = inputBitmap.getWidth();
int height = inputBitmap.getHeight();
float scaleWidth = ((float) cropSize) / width;
float scaleHeight = ((float) cropSize) / height;
//矩阵
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
/* 将输入图片通过矩阵变换得到416*416大小的新图片 */
Bitmap croppedBitmap = Bitmap.createBitmap(inputBitmap, 0, 0, width, height, matrix, true);
Bitmap draw = croppedBitmap.copy(Bitmap.Config.ARGB_8888, true);
++timestamp;
final long currTimestamp = timestamp;
LOGGER.i("Preparing image " + currTimestamp + " for detection in bg thread.");
/* 利用分类器classifier对图片进行预测分析得到图片为每个分类的概率. 比较耗时 */
LOGGER.i("Running detection on image " + currTimestamp);
final long startTime = SystemClock.uptimeMillis();
/* 核心检测 */
final List<Classifier.Recognition> results = detector.recognizeImage(croppedBitmap);
/* 计算检测时间 */
long lastProcessingTimeMs = SystemClock.uptimeMillis() - startTime;
/* 检测出多少对象 */
Log.e("CHECK", "run: " + results.size());
/* 检测时间 */
Log.i("Time Spent: ", lastProcessingTimeMs + "ms");
/* 筛选通过最低置信度阈值的识别结果 */
final List<Classifier.Recognition> mappedRecognitions = new LinkedList<>();
for (final Classifier.Recognition result : results)
{
final RectF location = result.getLocation();
if (location != null && result.getConfidence() >= minimumConfidence)
{
result.setLocation(location);
/* 将通过最低置信度的结果添加到新List */
mappedRecognitions.add(result);
//识别结果
Log.e("result: ", result.getTitle() + result.getConfidence());
drawBitmap(result, draw);
}
}
return gson.toJson(mappedRecognitions.size() > 0 ? mappedRecognitions : recognitions);
// //最终结果
// if (mappedRecognitions.size() != 0) {
// /* 排列出最高置信度的结果 */
// Collections.sort(mappedRecognitions, (o1, o2) -> (int) (o1.getConfidence() - o2.getConfidence()));
// Log.e("SUCCESS", String.valueOf(mappedRecognitions.get(0).getConfidence()));
// return mappedRecognitions.get(0).getTitle();
// } else {
// Log.e("ERROR", "识别错误");
// return "car";
// }
}
private void drawBitmap(Classifier.Recognition result, Bitmap resultBitmap)
{
final Canvas canvas = new Canvas(resultBitmap);
final Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2.0f);
canvas.drawRect(result.getLocation(), paint);
SaveBitmap = resultBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
}

@ -185,4 +185,34 @@
android:layout_weight="1"
android:text="立即崩溃" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_os_shapecolor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="3dp"
android:layout_weight="1"
android:text="开源\n形状颜色识别" />
<Button
android:id="@+id/btn_os_trafficsign"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="3dp"
android:layout_weight="1"
android:text="开源\n交通标志识别" />
<Button
android:id="@+id/btn_os_vehicle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="3dp"
android:layout_weight="1"
android:text="开源\n车型识别" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,3 @@
@echo off
git push
pause

@ -25,10 +25,7 @@
"variantName": "debug",
"isDebuggableEnabled": true,
"validAbiList": [
"ARMEABI_V7A",
"ARM64_V8A",
"X86",
"X86_64"
"ARM64_V8A"
],
"buildTargetSet": [
"opencv_jni_shared"
@ -128,6 +125,7 @@
"rootBuildGradleFolder": "F:\\Android-APK\\MainCar",
"sdkFolder": "D:\\Android_SDK",
"isBuildOnlyTargetAbiEnabled": true,
"ideBuildTargetAbi": "arm64-v8a,armeabi-v7a,armeabi",
"isCmakeBuildCohabitationEnabled": false,
"isPrefabEnabled": false
},

@ -11,7 +11,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -2145092568
"memoizedHashCode": -124854207
},
{
"level_": 0,
@ -25,7 +25,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1070678757
"memoizedHashCode": 949559604
},
{
"level_": 0,
@ -39,6 +39,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 1022864176
"memoizedHashCode": -1251864759
}
]

@ -11,7 +11,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 1208877764
"memoizedHashCode": -1065851171
},
{
"level_": 0,
@ -25,7 +25,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1843829769
"memoizedHashCode": 176408592
},
{
"level_": 0,
@ -39,6 +39,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 2135484110
"memoizedHashCode": -139244825
}
]

@ -189,3 +189,12 @@ generate_cxx_metadata
create-invalidation-state 15ms
generate_cxx_metadata completed in 20ms
# C/C++ build system timings
generate_cxx_metadata
create-invalidation-state 21ms
generate_cxx_metadata completed in 26ms
# C/C++ build system timings
# C/C++ build system timings

@ -11,7 +11,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -900999380
"memoizedHashCode": 1119238981
},
{
"level_": 0,
@ -25,7 +25,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 1031690335
"memoizedHashCode": -1243038600
},
{
"level_": 0,
@ -39,6 +39,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 1830489698
"memoizedHashCode": -444239237
}
]

@ -11,7 +11,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -979162050
"memoizedHashCode": 1041076311
},
{
"level_": 0,
@ -25,7 +25,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1733813153
"memoizedHashCode": 286425208
},
{
"level_": 0,
@ -39,6 +39,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1316102415
"memoizedHashCode": 704135946
}
]

@ -105,3 +105,10 @@ generate_cxx_metadata
create-invalidation-state 11ms
generate_cxx_metadata completed in 17ms
# C/C++ build system timings
generate_cxx_metadata
create-invalidation-state 18ms
generate_cxx_metadata completed in 23ms
# C/C++ build system timings

@ -11,7 +11,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -2068480099
"memoizedHashCode": 783740077
},
{
"level_": 0,
@ -25,7 +25,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 1874572633
"memoizedHashCode": 431825513
},
{
"level_": 0,
@ -39,6 +39,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 663008979
"memoizedHashCode": -779738141
}
]

@ -11,6 +11,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1169450043
"memoizedHashCode": 850788318
}
]

@ -1103,3 +1103,51 @@ create_cxx_tasks
create-initial-cxx-model completed in 92ms
create_cxx_tasks completed in 93ms
# C/C++ build system timings
create_cxx_tasks
create-initial-cxx-model
create-module-model
create-cmake-model 34ms
create-module-model completed in 36ms
create-module-model
create-cmake-model 32ms
create-module-model completed in 33ms
create-initial-cxx-model completed in 88ms
create_cxx_tasks completed in 89ms
# C/C++ build system timings
create_cxx_tasks
create-initial-cxx-model
create-module-model
create-cmake-model 31ms
create-module-model completed in 33ms
create-module-model
create-cmake-model 41ms
create-module-model completed in 44ms
create-initial-cxx-model completed in 95ms
create_cxx_tasks completed in 96ms
# C/C++ build system timings
create_cxx_tasks
create-initial-cxx-model
create-module-model
create-cmake-model 36ms
create-module-model completed in 38ms
create-module-model
create-cmake-model 34ms
create-module-model completed in 36ms
create-initial-cxx-model completed in 88ms
create_cxx_tasks completed in 89ms
# C/C++ build system timings
create_cxx_tasks
create-initial-cxx-model
create-module-model
create-cmake-model 33ms
create-module-model completed in 36ms
create-module-model
create-cmake-model 30ms
create-module-model completed in 32ms
create-initial-cxx-model completed in 85ms
create_cxx_tasks completed in 87ms

@ -11,7 +11,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -327415425
"memoizedHashCode": 1692822936
},
{
"level_": 0,
@ -25,7 +25,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 464772678
"memoizedHashCode": -1809956257
},
{
"level_": 0,
@ -39,7 +39,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 1169233871
"memoizedHashCode": -1105495064
},
{
"level_": 0,
@ -53,7 +53,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1262919355
"memoizedHashCode": 757319006
},
{
"level_": 0,
@ -67,7 +67,7 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": 2139358359
"memoizedHashCode": -135370576
},
{
"level_": 0,
@ -81,6 +81,6 @@
"fieldsDescending": {}
},
"memoizedSize": -1,
"memoizedHashCode": -1819628718
"memoizedHashCode": 200609643
}
]
Loading…
Cancel
Save