Files
MainCarRemoteControl/app/src/main/java/com/uns/maincar/gui/MainActivity.java
T
UnknownObject f9bb7d9487 1. add ocr license
2. add hyper-lpr function
3. add text filter
4. add commits
2022-11-13 23:41:47 +08:00

758 lines
29 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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为Wififalse为串口
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();
}
}