758 lines
29 KiB
Java
758 lines
29 KiB
Java
/*
|
||
* Copyright (c) 2022. UnknownNetworkService Group
|
||
* This file is created by UnknownObject at 2022 - 9 - 18
|
||
*/
|
||
|
||
package com.uns.maincar.gui;
|
||
|
||
import android.annotation.SuppressLint;
|
||
import android.content.Context;
|
||
import android.content.Intent;
|
||
import android.graphics.Bitmap;
|
||
import android.graphics.BitmapFactory;
|
||
import android.net.DhcpInfo;
|
||
import android.net.wifi.WifiManager;
|
||
import android.os.Bundle;
|
||
import android.os.Handler;
|
||
import android.os.Message;
|
||
import android.text.format.Formatter;
|
||
import android.text.method.ScrollingMovementMethod;
|
||
import android.util.Log;
|
||
import android.widget.EditText;
|
||
import android.widget.ImageView;
|
||
import android.widget.TextView;
|
||
import android.widget.Toast;
|
||
|
||
import androidx.annotation.Nullable;
|
||
import androidx.appcompat.app.AppCompatActivity;
|
||
|
||
import com.bkrcl.control_car_video.camerautil.CameraCommandUtil;
|
||
import com.bkrcl.control_car_video.camerautil.SearchCameraUtil;
|
||
import com.uns.maincar.R;
|
||
import com.uns.maincar.communication.CommandDecoder;
|
||
import com.uns.maincar.communication.CommandEncoder;
|
||
import com.uns.maincar.communication.DataTransferCore;
|
||
import com.uns.maincar.communication.SerialPortTransferCore;
|
||
import com.uns.maincar.communication.WifiTransferCore;
|
||
import com.uns.maincar.constants.Commands;
|
||
import com.uns.maincar.constants.Flags;
|
||
import com.uns.maincar.constants.Flags.TrafficLightColors;
|
||
import com.uns.maincar.constants.GlobalSignType;
|
||
import com.uns.maincar.cpp_interface.CarLicense;
|
||
import com.uns.maincar.cpp_interface.EnvTest;
|
||
import com.uns.maincar.cpp_interface.MainCarAES;
|
||
import com.uns.maincar.cpp_interface.OCR;
|
||
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.tools.ImageReleaser;
|
||
import com.uns.maincar.tools.OCRDataReleaser;
|
||
import com.uns.maincar.tools.TextFilter;
|
||
|
||
import java.io.UnsupportedEncodingException;
|
||
import java.util.ArrayList;
|
||
import java.util.Objects;
|
||
|
||
public class MainActivity extends AppCompatActivity
|
||
{
|
||
//数据接收处理器
|
||
private final Handler recvHandler;
|
||
//主车相机地址,默认值不重要
|
||
private String IPCamera = "192.168.1.101:81";
|
||
//摄像头当前图像
|
||
private Bitmap currImage;
|
||
//存储小车的IP
|
||
private String IPCar;
|
||
//通信客户端
|
||
private DataTransferCore dtc_client;
|
||
//DHCP相关信息,用于获取IP地址
|
||
private DhcpInfo dhcpInfo;
|
||
//WIFI管理器
|
||
private WifiManager wifiManager;
|
||
//控件——存储从摄像头获取到的图像
|
||
private ImageView pic_received;
|
||
//控件——存储Toast的内容,由ToastLog()进行管理
|
||
private TextView text_toast;
|
||
//控制主车相机
|
||
private CameraCommandUtil cameraCommandUtil;
|
||
//寻找主车相机
|
||
private SearchCameraUtil searchCameraUtil = null;
|
||
//程序状态,通过所有自检后会设置为true
|
||
private boolean SystemStatus = false;
|
||
//文件状态,获取到存储权限并释放完毕所有文件会设置为true
|
||
private boolean FileStatus = false;
|
||
//申请存储空间使用的请求码
|
||
private final int permission_request_code = 0x100942;
|
||
//串口通信的设备名
|
||
private final String SerialPortPath = "/dev/ttyS4";
|
||
//通信通道标志,true为Wifi,false为串口
|
||
private final boolean CommunicationUsingWifi = true;
|
||
//调试用16进制数组
|
||
private final String[] byte_str = {
|
||
"0x00", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", "0x08", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F",
|
||
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1A", "0x1B", "0x1C", "0x1D", "0x1E", "0x1F",
|
||
"0x20", "0x21", "0x22", "0x23", "0x24", "0x25", "0x26", "0x27", "0x28", "0x29", "0x2A", "0x2B", "0x2C", "0x2D", "0x2E", "0x2F",
|
||
"0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "0x39", "0x3A", "0x3B", "0x3C", "0x3D", "0x3E", "0x3F",
|
||
"0x40", "0x41", "0x42", "0x43", "0x44", "0x45", "0x46", "0x47", "0x48", "0x49", "0x4A", "0x4B", "0x4C", "0x4D", "0x4E", "0x4F",
|
||
"0x50", "0x51", "0x52", "0x53", "0x54", "0x55", "0x56", "0x57", "0x58", "0x59", "0x5A", "0x5B", "0x5C", "0x5D", "0x5E", "0x5F",
|
||
"0x60", "0x61", "0x62", "0x63", "0x64", "0x65", "0x66", "0x67", "0x68", "0x69", "0x6A", "0x6B", "0x6C", "0x6D", "0x6E", "0x6F",
|
||
"0x70", "0x71", "0x72", "0x73", "0x74", "0x75", "0x76", "0x77", "0x78", "0x79", "0x7A", "0x7B", "0x7C", "0x7D", "0x7E", "0x7F",
|
||
"0x80", "0x81", "0x82", "0x83", "0x84", "0x85", "0x86", "0x87", "0x88", "0x89", "0x8A", "0x8B", "0x8C", "0x8D", "0x8E", "0x8F",
|
||
"0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96", "0x97", "0x98", "0x99", "0x9A", "0x9B", "0x9C", "0x9D", "0x9E", "0x9F",
|
||
"0xA0", "0xA1", "0xA2", "0xA3", "0xA4", "0xA5", "0xA6", "0xA7", "0xA8", "0xA9", "0xAA", "0xAB", "0xAC", "0xAD", "0xAE", "0xAF",
|
||
"0xB0", "0xB1", "0xB2", "0xB3", "0xB4", "0xB5", "0xB6", "0xB7", "0xB8", "0xB9", "0xBA", "0xBB", "0xBC", "0xBD", "0xBE", "0xBF",
|
||
"0xC0", "0xC1", "0xC2", "0xC3", "0xC4", "0xC5", "0xC6", "0xC7", "0xC8", "0xC9", "0xCA", "0xCB", "0xCC", "0xCD", "0xCE", "0xCF",
|
||
"0xD0", "0xD1", "0xD2", "0xD3", "0xD4", "0xD5", "0xD6", "0xD7", "0xD8", "0xD9", "0xDA", "0xDB", "0xDC", "0xDD", "0xDE", "0xDF",
|
||
"0xE0", "0xE1", "0xE2", "0xE3", "0xE4", "0xE5", "0xE6", "0xE7", "0xE8", "0xE9", "0xEA", "0xEB", "0xEC", "0xED", "0xEE", "0xEF",
|
||
"0xF0", "0xF1", "0xF2", "0xF3", "0xF4", "0xF5", "0xF6", "0xF7", "0xF8", "0xF9", "0xFA", "0xFB", "0xFC", "0xFD", "0xFE", "0xFF"};
|
||
|
||
static
|
||
{
|
||
System.loadLibrary("opencv_support");
|
||
}
|
||
|
||
//原生函数导入,用于长按保存的功能
|
||
private static native boolean SaveImage(Bitmap img, String time);
|
||
|
||
@SuppressLint("HandlerLeak")
|
||
public MainActivity()
|
||
{
|
||
//接收内部消息的处理器,用于处理内部消息
|
||
recvHandler = new Handler()
|
||
{
|
||
@Override
|
||
public void handleMessage(Message msg)
|
||
{
|
||
super.handleMessage(msg);
|
||
//内部消息:收到图片;执行操作:更新GUI上的图片
|
||
if (msg.what == Flags.RECEIVED_IMAGE)
|
||
pic_received.setImageBitmap(currImage);
|
||
//内部消息:收到主车数据;执行操作:解析指令并执行
|
||
if (msg.what == Flags.RECEIVED_CAR_DATA)
|
||
{
|
||
byte[] recv = (byte[]) msg.obj;
|
||
if (recv != null)
|
||
{
|
||
//打印接收到的指令
|
||
ToastLog("RECV: [" + ByteArray2String(recv) + "]", true, false);
|
||
//解析指令
|
||
CommandDecoder decoder = new CommandDecoder(recv);
|
||
if (decoder.CommandReady())
|
||
{
|
||
ToastLog("Command Decode Ready.", false, false);
|
||
Thread th_run_command = new Thread(() ->
|
||
{
|
||
switch (decoder.GetMainCommand())
|
||
{
|
||
//收到全自动指令,返回程序自检状态
|
||
case Commands.RECEIVE_FULL_AUTO:
|
||
dtc_client.Send(SystemStatusCommand());
|
||
break;
|
||
//收到QR指令,开始识别二维码,回传识别成功的数据
|
||
case Commands.RECEIVE_QR:
|
||
byte[] cmd = RecognizeQrCode();
|
||
if (cmd[2] == Commands.QR_FAILED)
|
||
dtc_client.Send(cmd);
|
||
else
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.QR_SUCCESS_1, cmd[0], cmd[1], cmd[2]));
|
||
Sleep(500);
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.QR_SUCCESS_2, cmd[3], cmd[4], cmd[5]));
|
||
}
|
||
break;
|
||
//收到TRAFFIC_LIGHT指令,开始识别交通灯,回传识别成功的数据
|
||
case Commands.RECEIVE_TRAFFIC_LIGHT:
|
||
dtc_client.Send(RecognizeTrafficLight());
|
||
break;
|
||
//收到SHAPE_COLOR指令,开始识别形状颜色,回传识别成功的数据
|
||
case Commands.RECEIVE_SHAPE_COLOR:
|
||
dtc_client.Send(RecognizeShapeColor());
|
||
break;
|
||
//收到CAR_ID指令,开始识别车牌号,回传识别成功的数据
|
||
case Commands.RECEIVE_CAR_ID:
|
||
RecognizeCarID();
|
||
break;
|
||
//收到TRAFFIC_SIGN指令,开始识别交通标志,回传识别成功的数据
|
||
case Commands.RECEIVE_TRAFFIC_SIGN:
|
||
dtc_client.Send(RecognizeTrafficSign());
|
||
break;
|
||
//收到OCR指令,开始识别文本,回传识别成功的数据
|
||
case Commands.RECEIVE_TEXT_OCR:
|
||
OCRRecognizeText();
|
||
break;
|
||
//收到未知指令,回传异常指令,表示无法解析当前指令
|
||
default:
|
||
CommandEncoder error = new CommandEncoder();
|
||
dtc_client.Send(error.GenerateCommand(Commands.CMD_NOT_MATCH, (byte) 0x00, (byte) 0x00, (byte) 0x00));
|
||
break;
|
||
}
|
||
});
|
||
th_run_command.start();
|
||
}
|
||
//指令解析失败,回传异常指令,表示无法解析当前指令
|
||
else
|
||
{
|
||
CommandEncoder error = new CommandEncoder();
|
||
dtc_client.ThreadSend(error.GenerateCommand(Commands.CMD_NOT_MATCH, (byte) 0x00, (byte) 0x00, (byte) 0x00));
|
||
}
|
||
}
|
||
//收到NULL,输出日志,不做操作
|
||
else
|
||
ToastLog("NULL Received", true, false);
|
||
|
||
}
|
||
//内部消息:打印数组;操作:打印收到的数组
|
||
if (msg.what == Flags.PRINT_DATA_ARRAY)
|
||
{
|
||
byte[] data = (byte[]) msg.obj;
|
||
if (data != null)
|
||
ToastLog("SEND: [" + ByteArray2String(data) + "]", false, false);
|
||
}
|
||
//内部消息:打印日志;操作:打印收到的日志
|
||
if (msg.what == Flags.PRINT_SYSTEM_LOG)
|
||
{
|
||
String str = (String) msg.obj;
|
||
if (str != null)
|
||
ToastLog(str, false, false);
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
//处理二维码数据,使用从C++代码中导出的算法
|
||
private byte[] ProcessQRData(ArrayList<String> qr_data)
|
||
{
|
||
return MainCarAES.CalcAES(qr_data.get(0));
|
||
}
|
||
|
||
//获取程序自检指令,根据自检状态返回成功或失败
|
||
private byte[] SystemStatusCommand()
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
if (SystemStatus && FileStatus)
|
||
return encoder.GenerateCommand(Commands.STATUS_SUCCESS, (byte) 0, (byte) 0, (byte) 0);
|
||
else
|
||
return encoder.GenerateCommand(Commands.STATUS_FAILED, (byte) 0, (byte) 0, (byte) 0);
|
||
}
|
||
|
||
//识别二维码
|
||
private byte[] RecognizeQrCode()
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
ArrayList<String> qr_result = new ArrayList<>();
|
||
if (!QRDecoder.BeginQRDecode(currImage))
|
||
return encoder.GenerateCommand(Commands.QR_FAILED, (byte) 0, (byte) 0, (byte) 0);
|
||
while (QRDecoder.HasNextCode())
|
||
qr_result.add(QRDecoder.DecodeNextQR());
|
||
if (qr_result.size() <= 0)
|
||
return encoder.GenerateCommand(Commands.QR_FAILED, (byte) 0, (byte) 0, (byte) 0);
|
||
else
|
||
{
|
||
qr_result.forEach(qr -> ToastLog(qr, false, true));
|
||
return ProcessQRData(qr_result);
|
||
}
|
||
}
|
||
|
||
//识别交通灯
|
||
private byte[] RecognizeTrafficLight()
|
||
{
|
||
TrafficLightColors color = TrafficLight.RecognizeTrafficLight(currImage);
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
switch (color)
|
||
{
|
||
case RED:
|
||
return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_SUCCESS, Commands.TRAFFIC_LIGHT_RED, (byte) 0, (byte) 0);
|
||
case NULL:
|
||
return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_FAILED, (byte) 0, (byte) 0, (byte) 0);
|
||
case GREEN:
|
||
return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_SUCCESS, Commands.TRAFFIC_LIGHT_GREEN, (byte) 0, (byte) 0);
|
||
case YELLOW:
|
||
return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_SUCCESS, Commands.TRAFFIC_LIGHT_YELLOW, (byte) 0, (byte) 0);
|
||
}
|
||
return encoder.GenerateCommand(Commands.TRAFFIC_LIGHT_FAILED, (byte) -1, (byte) -1, (byte) -1);
|
||
}
|
||
|
||
//识别形状颜色
|
||
private byte[] RecognizeShapeColor()
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
if (!ShapeColor.RecognizeEverything(currImage))
|
||
return encoder.GenerateCommand(Commands.COLOR_SHAPE_FAILED, (byte) 0, (byte) 0, (byte) 0);
|
||
else
|
||
{
|
||
byte a = 0, b = 0, c = 0;
|
||
//测试用输出
|
||
/*ToastLog("C-R-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.RED), false, false);
|
||
ToastLog("C-BL-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.BLACK), false, false);
|
||
ToastLog("C-G-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.GREEN), false, false);
|
||
ToastLog("C-BU-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.BLUE), false, false);
|
||
ToastLog("C-C-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.CYAN), false, false);
|
||
ToastLog("C-P-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.PURPLE), false, false);
|
||
ToastLog("C-W-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.WHITE), false, false);
|
||
ToastLog("C-Y-"+ShapeColor.LookupResult(GlobalShape.CIRCLE, GlobalColor.YELLOW), false, false);
|
||
ToastLog("S-R-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.RED), false, false);
|
||
ToastLog("S-BL-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.BLACK), false, false);
|
||
ToastLog("S-G-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.GREEN), false, false);
|
||
ToastLog("S-BU-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.BLUE), false, false);
|
||
ToastLog("S-C-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.CYAN), false, false);
|
||
ToastLog("S-P-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.PURPLE), false, false);
|
||
ToastLog("S-W-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.WHITE), false, false);
|
||
ToastLog("S-Y-"+ShapeColor.LookupResult(GlobalShape.STAR, GlobalColor.YELLOW), false, false);
|
||
ToastLog("s-R-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.RED), false, false);
|
||
ToastLog("s-BL-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.BLACK), false, false);
|
||
ToastLog("s-G-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.GREEN), false, false);
|
||
ToastLog("s-BU-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.BLUE), false, false);
|
||
ToastLog("s-C-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.CYAN), false, false);
|
||
ToastLog("s-P-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.PURPLE), false, false);
|
||
ToastLog("s-W-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.WHITE), false, false);
|
||
ToastLog("s-Y-"+ShapeColor.LookupResult(GlobalShape.SQUARE, GlobalColor.YELLOW), false, false);
|
||
ToastLog("R-R-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.RED), false, false);
|
||
ToastLog("R-BL-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.BLACK), false, false);
|
||
ToastLog("R-G-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.GREEN), false, false);
|
||
ToastLog("R-BU-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.BLUE), false, false);
|
||
ToastLog("R-C-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.CYAN), false, false);
|
||
ToastLog("R-P-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.PURPLE), false, false);
|
||
ToastLog("R-W-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.WHITE), false, false);
|
||
ToastLog("R-Y-"+ShapeColor.LookupResult(GlobalShape.RECTANGLE, GlobalColor.YELLOW), false, false);
|
||
ToastLog("T-R-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.RED), false, false);
|
||
ToastLog("T-BL-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.BLACK), false, false);
|
||
ToastLog("T-G-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.GREEN), false, false);
|
||
ToastLog("T-BU-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.BLUE), false, false);
|
||
ToastLog("T-C-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.CYAN), false, false);
|
||
ToastLog("T-P-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.PURPLE), false, false);
|
||
ToastLog("T-W-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.WHITE), false, false);
|
||
ToastLog("T-Y-"+ShapeColor.LookupResult(GlobalShape.TRIANGLE, GlobalColor.YELLOW), false, false);*/
|
||
return encoder.GenerateCommand(Commands.COLOR_SHAPE_SUCCESS, a, b, c);
|
||
}
|
||
}
|
||
|
||
//识别车牌
|
||
private void RecognizeCarID()
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
// CarLicense.Result result = CarLicense.Recognize(currImage); //通过模板匹配识别车牌
|
||
// CarLicense.Result result = CarLicense.RecognizeByOCR(currImage); //通过OCR识别车牌
|
||
CarLicense.Result result = CarLicense.RecognizeByAI(currImage, this); //通过AI模型识别车牌
|
||
if (!result.Success())
|
||
{
|
||
//OCR识别的自动重试功能
|
||
/*final int OCR_MAX_RETRY = 5;
|
||
int retry_time = 0;
|
||
do
|
||
{
|
||
result = CarLicense.RecognizeByOCR(currImage);
|
||
Sleep(100);
|
||
retry_time++;
|
||
}while (result.isEmpty() && (retry_time <= OCR_MAX_RETRY));
|
||
if(retry_time > OCR_MAX_RETRY)
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.CAR_ID_FAILED, (byte) 0, (byte) 0, (byte) 0));
|
||
else
|
||
{
|
||
encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_FIRST);
|
||
encoder.AddData(result.GetFirstThreeBits());
|
||
dtc_client.Send(encoder.GenerateCommand());
|
||
Sleep(500);
|
||
encoder.Clear();
|
||
encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_SECOND);
|
||
encoder.AddData(result.GetLastThreeBits());
|
||
dtc_client.Send(encoder.GenerateCommand());
|
||
}*/
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.CAR_ID_FAILED, (byte) 0, (byte) 0, (byte) 0));
|
||
}
|
||
else
|
||
{
|
||
//车牌信息分两次发送
|
||
encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_FIRST);
|
||
encoder.AddData(result.GetFirstThreeBits());
|
||
dtc_client.Send(encoder.GenerateCommand());
|
||
Sleep(500);
|
||
encoder.Clear();
|
||
encoder.AddMainCommand(Commands.CAR_ID_SUCCESS_SECOND);
|
||
encoder.AddData(result.GetLastThreeBits());
|
||
dtc_client.Send(encoder.GenerateCommand());
|
||
}
|
||
}
|
||
|
||
//识别交通标志
|
||
private byte[] RecognizeTrafficSign()
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
GlobalSignType type = TrafficSign.SignRecognize(currImage);
|
||
if (type == GlobalSignType.Failure)
|
||
return encoder.GenerateCommand(Commands.TRAFFIC_SIGN_FAILED, (byte) 0, (byte) 0, (byte) 0);
|
||
else
|
||
{
|
||
encoder.AddMainCommand(Commands.TRAFFIC_SIGN_SUCCESS);
|
||
switch (type)
|
||
{
|
||
case NoEntry:
|
||
encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_NO_ENTRY, (byte) 0, (byte) 0);
|
||
break;
|
||
case StraightProhibited:
|
||
encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_NO_STRAIGHT, (byte) 0, (byte) 0);
|
||
break;
|
||
case TurnLeft:
|
||
encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_TURN_LEFT, (byte) 0, (byte) 0);
|
||
break;
|
||
case TurnRight:
|
||
encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_TURN_RIGHT, (byte) 0, (byte) 0);
|
||
break;
|
||
case GoStraight:
|
||
encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_STRAIGHT, (byte) 0, (byte) 0);
|
||
break;
|
||
case U_Turn:
|
||
encoder.AddData(Commands.TRAFFIC_SIGN_TYPE_U_TURN, (byte) 0, (byte) 0);
|
||
break;
|
||
}
|
||
return encoder.GenerateCommand();
|
||
}
|
||
}
|
||
|
||
//识别静态文本
|
||
private void OCRRecognizeText()
|
||
{
|
||
TextFilter filter = new TextFilter();
|
||
String str = filter.RemoveEmptyCharacter(OCR.DecodeImage(currImage));
|
||
ToastLog("OCR Result: [" + str + "]", false, true);
|
||
byte[] b_str;
|
||
try
|
||
{
|
||
b_str = str.getBytes("GBK");
|
||
}
|
||
catch (UnsupportedEncodingException e)
|
||
{
|
||
ToastLog("GBK Encoding is Not Supported", false, true);
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_FAILED, (byte) 0x00, (byte) 0x00, (byte) 0x00));
|
||
return;
|
||
}
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_SUCCESS, (byte) 0x00, (byte) 0x00, (byte) 0x00));
|
||
Sleep(900);
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_LENGTH, (byte) b_str.length, (byte) 0x00, (byte) b_str.length));
|
||
for (int i = 0; i < b_str.length; i += 2)
|
||
{
|
||
Sleep(500);
|
||
byte data_2 = ((i + 1) >= b_str.length ? 0x00 : b_str[i + 1]);
|
||
byte checksum = (byte) ((b_str[i] + data_2) % 0xFF);
|
||
byte main = ((i + 2) < b_str.length ? Commands.OCR_TEXT_DATA : Commands.OCR_TEXT_FINISH);
|
||
if (!dtc_client.SendEx(encoder.GenerateCommand(main, b_str[i], data_2, checksum), Commands.RECEIVE_OCR_DATA_OK, 2000))
|
||
{
|
||
dtc_client.Send(encoder.GenerateCommand(Commands.OCR_TEXT_FAILED, (byte) 0x00, (byte) 0x00, (byte) 0x00));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//数组转字符串,仅用于调试输出
|
||
private String ByteArray2String(byte[] arr)
|
||
{
|
||
StringBuilder msg_str = new StringBuilder();
|
||
for (byte b : arr)
|
||
msg_str.append(byte_str[b & 0xff]).append(" ");
|
||
return msg_str.toString();
|
||
}
|
||
|
||
//初始化图形界面
|
||
private void InitGUI()
|
||
{
|
||
pic_received = findViewById(R.id.camera_image);
|
||
text_toast = findViewById(R.id.text_toast);
|
||
|
||
text_toast.setMovementMethod(ScrollingMovementMethod.getInstance());
|
||
|
||
findViewById(R.id.btn_debug_send).setOnClickListener(view ->
|
||
{
|
||
byte[] data = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
|
||
dtc_client.ThreadSend(data);
|
||
});
|
||
|
||
findViewById(R.id.btn_camera_up).setOnClickListener(view ->
|
||
{
|
||
Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_UP, 5));
|
||
th_send.start();
|
||
});
|
||
|
||
findViewById(R.id.btn_camera_down).setOnClickListener(view ->
|
||
{
|
||
Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_DOWN, 5));
|
||
th_send.start();
|
||
});
|
||
|
||
findViewById(R.id.btn_camera_left).setOnClickListener(view ->
|
||
{
|
||
Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_LEFT, 5));
|
||
th_send.start();
|
||
});
|
||
|
||
findViewById(R.id.btn_camera_right).setOnClickListener(view ->
|
||
{
|
||
Thread th_send = new Thread(() -> cameraCommandUtil.postHttp(IPCamera, Flags.CAMERA_RIGHT, 5));
|
||
th_send.start();
|
||
});
|
||
|
||
findViewById(R.id.btn_send).setOnClickListener(view ->
|
||
{
|
||
try
|
||
{
|
||
byte cmd0 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd0)).getText().toString(), 16);
|
||
byte cmd1 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd1)).getText().toString(), 16);
|
||
byte cmd2 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd2)).getText().toString(), 16);
|
||
byte cmd3 = (byte) Integer.parseInt(((EditText) findViewById(R.id.edit_cmd3)).getText().toString(), 16);
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
byte[] cmd = encoder.GenerateCommand(cmd0, cmd1, cmd2, cmd3);
|
||
dtc_client.ThreadSend(cmd);
|
||
//print debug information
|
||
Message.obtain(recvHandler, Flags.PRINT_DATA_ARRAY, cmd).sendToTarget();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
ToastLog("Input Data Invalidate", true, false);
|
||
}
|
||
});
|
||
|
||
findViewById(R.id.btn_start_qr).setOnClickListener(view ->
|
||
{
|
||
ToastLog("QR Code Started", false, false);
|
||
ToastLog("QR Result: " + ByteArray2String(RecognizeQrCode()), false, false);
|
||
});
|
||
|
||
findViewById(R.id.btn_start_light).setOnClickListener(view ->
|
||
{
|
||
ToastLog("Traffic Light Started", false, false);
|
||
ToastLog("TL Result: " + ByteArray2String(RecognizeTrafficLight()), false, false);
|
||
});
|
||
|
||
findViewById(R.id.btn_start_color_shape).setOnClickListener(view ->
|
||
{
|
||
ToastLog("Color Shape Started", false, false);
|
||
ToastLog("CS Result: " + ByteArray2String(RecognizeShapeColor()), false, false);
|
||
});
|
||
|
||
findViewById(R.id.btn_start_car_id).setOnClickListener(view ->
|
||
{
|
||
ToastLog("Car ID Started", false, false);
|
||
Thread th_debug = new Thread(this::RecognizeCarID);
|
||
th_debug.start();
|
||
ToastLog("CID Finished", false, false);
|
||
});
|
||
|
||
findViewById(R.id.btn_start_sign).setOnClickListener(view ->
|
||
{
|
||
ToastLog("Traffic Sign Started", false, false);
|
||
ToastLog("TS Result: " + ByteArray2String(RecognizeTrafficSign()), false, false);
|
||
});
|
||
|
||
findViewById(R.id.btn_start_ocr).setOnClickListener(view ->
|
||
{
|
||
ToastLog("OCR Started", false, false);
|
||
/*ToastLog("OCR Result: " + OCR.DecodeImage(currImage), false, false);*/
|
||
Thread th_debug = new Thread(this::OCRRecognizeText);
|
||
th_debug.start();
|
||
});
|
||
|
||
findViewById(R.id.btn_tft_page_down).setOnClickListener(view ->
|
||
{
|
||
CommandEncoder encoder = new CommandEncoder();
|
||
dtc_client.ThreadSend(encoder.GenerateCommand(Commands.TFT_PAGE_DOWN, (byte) 0, (byte) 0, (byte) 0));
|
||
ToastLog("TFT Page Down Command Send.", false, true);
|
||
});
|
||
|
||
findViewById(R.id.btn_movement_control).setOnClickListener(view ->
|
||
{
|
||
startActivity(new Intent(this, MovementController.class));
|
||
});
|
||
|
||
findViewById(R.id.btn_crash).setOnClickListener(view ->
|
||
{
|
||
//崩溃按钮的作用:频繁调试时省去手动退出程序,清理后台的操作,节省时间。
|
||
dtc_client.DisableAutoReconnect();
|
||
dtc_client.CloseConnection(); //关闭通信
|
||
throw new NullPointerException(); //通过异常来崩溃。
|
||
});
|
||
|
||
findViewById(R.id.text_toast).setOnLongClickListener(view ->
|
||
{
|
||
ToastLog("Log Cleared", true, false);
|
||
((TextView) view).setText("");
|
||
return true;
|
||
});
|
||
|
||
findViewById(R.id.camera_image).setOnLongClickListener(view ->
|
||
{
|
||
String time = String.valueOf(System.currentTimeMillis());
|
||
if (SaveImage(currImage, time))
|
||
ToastLog("Image Saved", true, false);
|
||
else
|
||
ToastLog("Image Save Failure", true, false);
|
||
return true;
|
||
});
|
||
}
|
||
|
||
//打印日志
|
||
@SuppressLint("SetTextI18n")
|
||
private void ToastLog(String text, boolean real_toast, boolean on_thread)
|
||
{
|
||
if (text_toast == null)
|
||
text_toast = findViewById(R.id.text_toast);
|
||
if (real_toast)
|
||
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
|
||
Log.i("ToastBackup", text);
|
||
if (on_thread)
|
||
Message.obtain(recvHandler, Flags.PRINT_SYSTEM_LOG, text);
|
||
else
|
||
text_toast.setText(text_toast.getText().toString() + "\n" + text);
|
||
}
|
||
|
||
//等待一段时间
|
||
private void Sleep(long ms)
|
||
{
|
||
try
|
||
{
|
||
Thread.sleep(ms);
|
||
}
|
||
catch (InterruptedException ignored)
|
||
{
|
||
}
|
||
}
|
||
|
||
//启动寻找摄像头的线程
|
||
private void StartCameraImageUpdate(int duration)
|
||
{
|
||
Thread th_image = new Thread(() ->
|
||
{
|
||
while (true)
|
||
{
|
||
currImage = cameraCommandUtil.httpForImage(IPCamera);
|
||
recvHandler.sendEmptyMessage(Flags.RECEIVED_IMAGE);
|
||
Sleep(duration);
|
||
}
|
||
});
|
||
th_image.start();
|
||
ToastLog("Camera Update Thread: " + th_image.getState(), false, true);
|
||
}
|
||
|
||
@Override
|
||
protected void onCreate(Bundle savedInstanceState)
|
||
{
|
||
super.onCreate(savedInstanceState);
|
||
setContentView(R.layout.activity_main);
|
||
|
||
Objects.requireNonNull(getSupportActionBar()).setTitle("主车远端服务程序");
|
||
|
||
//初始化图形用户界面
|
||
InitGUI();
|
||
ToastLog("GUI Init Finished.", false, false);
|
||
|
||
//检查NDK及引用库
|
||
ToastLog(EnvTest.TestNDK(), false, false);
|
||
ToastLog(EnvTest.TestOpenCV(), false, false);
|
||
ToastLog(EnvTest.TestTrafficLightReco(), false, false);
|
||
ToastLog(EnvTest.TestImageProcessor(), false, false);
|
||
ToastLog(EnvTest.TestColorReco(), false, false);
|
||
ToastLog(EnvTest.TestShapeReco(), false, false);
|
||
ToastLog(EnvTest.TestShapeColorReco(), false, false);
|
||
ToastLog(EnvTest.TestCarLicenseReco(), false, false);
|
||
ToastLog(EnvTest.TestTrafficSignReco(), false, false);
|
||
ToastLog(EnvTest.TestOCRText(), false, false);
|
||
ToastLog(EnvTest.TestMainCarAES(), false, false);
|
||
|
||
byte[] demo = MainCarAES.CalcAES("ABCDEFGHabcdefgh");
|
||
if (demo == null)
|
||
ToastLog("AES Status: Error", false, false);
|
||
else
|
||
ToastLog("AES Status: " + ByteArray2String(demo), false, false);
|
||
|
||
//二维码扫描自检
|
||
ToastLog(QRDecoder.SelfTest(BitmapFactory.decodeResource(getResources(), R.drawable.qr_decode_test)), false, false);
|
||
|
||
//获取主车IP地址
|
||
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||
dhcpInfo = wifiManager.getDhcpInfo();
|
||
IPCar = Formatter.formatIpAddress(dhcpInfo.gateway);
|
||
ToastLog("DHCP Server Address: " + IPCar, false, false);
|
||
|
||
//建立连接
|
||
if (CommunicationUsingWifi)
|
||
dtc_client = new WifiTransferCore(IPCar, 60000, recvHandler);
|
||
else
|
||
dtc_client = new SerialPortTransferCore(SerialPortPath, 115200, recvHandler);
|
||
Thread th_connect = new Thread(() ->
|
||
{
|
||
if (dtc_client.Connect())
|
||
ToastLog("Client Connected", false, true);
|
||
else
|
||
ToastLog("Client Connect Failed", false, true);
|
||
});
|
||
th_connect.start();
|
||
while (th_connect.isAlive())
|
||
Sleep(10); //Wait for Connection Thread
|
||
dtc_client.EnableAutoReconnect(); //启动自动重连
|
||
|
||
//初始化摄像头控制
|
||
cameraCommandUtil = new CameraCommandUtil();
|
||
ToastLog("CameraCommandUtil Ready.", false, false);
|
||
|
||
//寻找摄像头,获取其IP地址
|
||
Thread camera_thread = new Thread(() ->
|
||
{
|
||
IPCamera = null;
|
||
ToastLog("CameraSearchThread: Camera Thread Start", false, true);
|
||
while (IPCamera == null || IPCamera.equals(""))
|
||
{
|
||
searchCameraUtil = new SearchCameraUtil();
|
||
try
|
||
{
|
||
IPCamera = searchCameraUtil.send();
|
||
}
|
||
catch (NullPointerException e)
|
||
{
|
||
IPCamera = null;
|
||
}
|
||
}
|
||
ToastLog("CameraSearchThread: Camera Found. IP: " + IPCamera, false, true);
|
||
IPCamera = IPCamera + ":81";
|
||
ToastLog("Camera Address: " + IPCamera, false, true);
|
||
StartCameraImageUpdate(50);
|
||
//这里是程序初始化的最后一步,能到达此处标志着自检通过
|
||
SystemStatus = true;
|
||
});
|
||
camera_thread.start();
|
||
|
||
//获取外部存储权限并释放识别使用的标准图和OCR的训练模型
|
||
Intent permission_page = new Intent(this, PermissionGetter.class);
|
||
startActivityForResult(permission_page, permission_request_code);
|
||
}
|
||
|
||
@Override
|
||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
|
||
{
|
||
super.onActivityResult(requestCode, resultCode, data);
|
||
if (requestCode == permission_request_code)
|
||
{
|
||
if (resultCode == RESULT_OK)
|
||
{
|
||
ImageReleaser releaser = new ImageReleaser(this);
|
||
OCRDataReleaser releaser_ocr = new OCRDataReleaser(this);
|
||
FileStatus = (releaser.ReleaseAllImage() && releaser_ocr.ReleaseAllFiles());
|
||
ToastLog(releaser.toString(), false, false);
|
||
ToastLog(releaser_ocr.toString(), false, false);
|
||
if (FileStatus)
|
||
ToastLog(OCR.SelfTest(this), false, false); //OCR光学字符识别自检
|
||
}
|
||
else
|
||
FileStatus = false;
|
||
}
|
||
}
|
||
|
||
@Override
|
||
protected void onDestroy()
|
||
{
|
||
super.onDestroy();
|
||
//Activity销毁时关闭通信
|
||
dtc_client.DisableAutoReconnect();
|
||
dtc_client.CloseConnection();
|
||
}
|
||
} |