Compare commits

..

No commits in common. 'main' and 'main' have entirely different histories.
main ... main

@ -1,34 +1,2 @@
# 垃圾分类识别系统
系统简介:
垃圾识别: 系统能够对用户提供的垃圾图片进行分析和处理,快速而精准地判定垃圾的种类,并将识别结果反馈给用户。
垃圾桶定位: 系统获取用户当前位置及人工标注的附近垃圾桶位置信息,并计算路径,帮助用户找到最近的垃圾桶。
用户反馈: 系统设有用户反馈功能。用户可以提交垃圾分类的疑问、问题和反馈。这些数据后续会进行筛选和分析,用于进一步优化系统的识别算法和流程。
垃圾分类知识竞答: 系统提供给用户有关垃圾分类的选择题或判断题,用户可以进行作答,帮助用户提升垃圾分类的相关知识
配置环境:
Android版本
minSDK 26
TargetSDK 33
python环境
python 3.7.6
torchvision 0.13.1
tensorflow 1.14.0
pytorch 1.12.1
mysql版本 8.10
# garbage

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 MiB

@ -1,81 +0,0 @@
'''
数据样本分析
画出数据量条形图
画出图像分辨率散点图
'''
import os
import PIL.Image as Image
import matplotlib.pyplot as plt
import numpy as np
def plot_resolution(dataset_root_path):
img_size_list = [] # 存储图片长宽数据
for root, dirs, files in os.walk(dataset_root_path):
for file_i in files:
file_i_full_path = os.path.join(root, file_i)
img_i = Image.open(file_i_full_path)
img_i_size = img_i.size # 获取单张图像的长宽
img_size_list.append(img_i_size)
print(img_size_list) #
width_list = [img_size_list[i][0] for i in range(len(img_size_list))]#提取所有图片的宽度信息,构建一个新的列表
height_list = [img_size_list[i][1] for i in range(len(img_size_list))]#提取所有图片的高度信息,构建一个新的列表
# print(width_list) # 640
# print(height_list) # 346
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置中文字体
plt.rcParams["font.size"] = 8
plt.rcParams["axes.unicode_minus"] = False # 该语句解决图像中的“-”负号的乱码问题
plt.scatter(width_list, height_list, s=1)
plt.xlabel("")
plt.ylabel("")
plt.title("图像宽高分布")
plt.show()
# 画出条形图
def plot_bar(dataset_root_path):
file_name_list = []
file_num_list = []
for root, dirs, files in os.walk(dataset_root_path):
if len(dirs) != 0:
for dir_i in dirs:
file_name_list.append(dir_i)
file_num_list.append(len(files))
file_num_list = file_num_list[1:]
# 求均值,并把均值以横线形式显示出来
mean = np.mean(file_num_list)
print("mean = ", mean)
bar_positions = np.arange(len(file_name_list))
fig, ax = plt.subplots() # 定义画的区间和子画
ax.bar(bar_positions, file_num_list, 0.5) # 画柱图,参数:柱间的距离,柱的值,柱的宽度
ax.plot(bar_positions, [mean for i in bar_positions], color="red") # 显示平均值
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置中文字体
plt.rcParams["font.size"] = 8
plt.rcParams["axes.unicode_minus"] = False # 该语句解决图像中的“-”负号的乱码问题
ax.set_xticks(bar_positions) # 设置x轴的刻度
ax.set_xticklabels(file_name_list, rotation=90) # 设置x轴的标签
ax.set_ylabel("类别数量")
ax.set_title("数据分布图")
plt.show()
if __name__ == '__main__':
dataset_root_path = "dataset"
plot_resolution(dataset_root_path)
# plot_bar(dataset_root_path)

@ -1,42 +0,0 @@
from PIL import Image
import os
dataset_root_path = "dataset"
min = 200 # 短边
max = 2000 # 长边
ratio = 0.5 # 短边 / 长边
delete_list = [] # 所有图片的长宽数据
for root,dirs,files in os.walk(dataset_root_path):
for file_i in files:
file_i_full_path = os.path.join(root, file_i)#构建当前文件的完整路径
img_i = Image.open(file_i_full_path)#将其加载为一个图像对象
img_i_size = img_i.size # 获取单张图像的长宽
# 删除单边过短的图片
if img_i_size[0]<min or img_i_size[1]<min:
print(file_i_full_path, " 不满足要求")
delete_list.append(file_i_full_path)
# 删除单边过长的图片
if img_i_size[0] > max or img_i_size[1] > max:
print(file_i_full_path, " 不满足要求")
delete_list.append(file_i_full_path)
# 删除宽高比例不当的图片
long = img_i_size[0] if img_i_size[0] > img_i_size[1] else img_i_size[1]
short = img_i_size[0] if img_i_size[0] < img_i_size[1] else img_i_size[1]
if short / long < ratio:
print(file_i_full_path, " 不满足要求",img_i_size[0],img_i_size[1])
delete_list.append(file_i_full_path)
# print(delete_list)
for file_i in delete_list:
try:
print("正在删除",file_i)
os.remove(file_i)
except:
pass

@ -1,49 +0,0 @@
'''
使用翻转进行数据增强
'''
import os
import cv2
import numpy as np
# 水平翻转
def Horizontal(image):
return cv2.flip(image,1,dst=None) #水平镜像
# 垂直翻转
def Vertical(image):
return cv2.flip(image,0,dst=None) #垂直镜像
if __name__ == '__main__':
from_root = r"dataset"
save_root = r"enhance_dataset"
threshold = 200
for a,b,c in os.walk(from_root):
for file_i in c:
file_i_path = os.path.join(a,file_i)
split = os.path.split(file_i_path)
dir_loc = os.path.split(split[0])[1]
save_path = os.path.join(save_root,dir_loc)
print(file_i_path)
print(save_path)
if os.path.isdir(save_path) == False:
os.makedirs(save_path)
img_i = cv2.imdecode(np.fromfile(file_i_path, dtype=np.uint8),-1) # 读取图片
cv2.imencode('.jpg', img_i)[1].tofile(os.path.join(save_path, file_i[:-5] + "_original.jpg")) # 保存图片
if len(c) < threshold:
img_horizontal = Horizontal(img_i)
cv2.imencode('.jpg', img_horizontal)[1].tofile(os.path.join(save_path, file_i[:-5] + "_horizontal.jpg")) # 保存图片
img_vertical = Vertical(img_i)
cv2.imencode('.jpg', img_vertical)[1].tofile(os.path.join(save_path, file_i[:-5] + "_vertical.jpg")) # 保存图片
else:
pass

@ -1,23 +0,0 @@
import os
import random
img_root = r"enhance_dataset"
threshold = 300
for a,b,c in os.walk(img_root):
if len(c) > threshold:
delete_list = []
for file_i in c:
file_i_full_path = os.path.join(a,file_i)
delete_list.append(file_i_full_path)
random.shuffle(delete_list)
print(delete_list)
delete_list = delete_list[threshold:]
for file_delete_i in delete_list:
os.remove(file_delete_i)
print("将会删除",file_delete_i)

@ -1,28 +0,0 @@
from torchvision.datasets import ImageFolder
import torch
from torchvision import transforms as T
from tqdm import tqdm
transform = T.Compose([
T.RandomResizedCrop(224),
T.ToTensor(),
])
def getStat(train_data):
train_loader = torch.utils.data.DataLoader(
train_data, batch_size=1, shuffle=False, num_workers=0, pin_memory=True)
mean = torch.zeros(3)
std = torch.zeros(3)
for X, _ in tqdm(train_loader):
for d in range(3):
mean[d] += X[:, d, :, :].mean() # N, C, H ,W
std[d] += X[:, d, :, :].std()
mean.div_(len(train_data))
std.div_(len(train_data))
return list(mean.numpy()), list(std.numpy())
if __name__ == '__main__':
train_dataset = ImageFolder(root=r'enhance_dataset', transform=transform)
print(getStat(train_dataset))

@ -1,40 +0,0 @@
import os
import random
train_ratio = 0.9 #训练集比例
test_ratio = 1-train_ratio #测试集比例
rootdata = r"dataset"
train_list, test_list = [],[]
class_flag = -1#初始类别标签
t=1
for a,b,c in os.walk(rootdata):#目录路径,子目录名,文件名
# if t==1:
# # print(a)
# print(b)
# print(len(c))
# t=-1
for i in range(0, int(len(c)*train_ratio)):#根据训练集比例确定训练集的文件数量
train_data = os.path.join(a, c[i])+'\t'+str(class_flag)+'\n'
# print('666'+train_data)
train_list.append(train_data)
for i in range(int(len(c) * train_ratio), len(c)):
test_data = os.path.join(a, c[i]) + '\t' + str(class_flag)+'\n'
test_list.append(test_data)
class_flag += 1
random.shuffle(train_list)#随机打乱训练集列表 train_list 中的元素顺序
random.shuffle(test_list)
with open('train.txt','w',encoding='UTF-8') as f:
for train_img in train_list:
f.write(str(train_img))#将训练集中的文件路径和类别标签写入文件 'train.txt',将其转换为字符串形式并写入文件。
with open('test.txt','w',encoding='UTF-8') as f:
for test_img in test_list:
f.write(test_img)

@ -1,124 +0,0 @@
import time
import torch
from torch import nn
from torch.utils.data import DataLoader
from utils import LoadData,WriteData
from torchvision.models import resnet18
def train(dataloader, model, loss_fn, optimizer,device):
size = len(dataloader.dataset)
avg_loss = 0
# 从数据加载器中读取batch一次读取多少张即批次数X(图片数据)y图片真实标签
for batch, (X, y) in enumerate(dataloader):#固定格式batch第几批数据不是批次大小Xy数值用括号
# 将数据存到显卡
X, y = X.to(device), y.to(device)
# 得到预测的结果pred
pred = model(X)
loss = loss_fn(pred, y)
avg_loss += loss
# 反向传播,更新模型参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每训练10次输出一次当前信息
if batch % 10 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
# 当一个epoch完了后返回平均 loss
avg_loss /= size
avg_loss = avg_loss.detach().cpu().numpy()
return avg_loss
def validate(dataloader, model, loss_fn, device):
size = len(dataloader.dataset)
# 将模型转为验证模式
model.eval()
# 初始化test_loss 和 correct 用来统计每次的误差
test_loss, correct = 0, 0
# 测试时模型参数不用更新所以no_gard()
# 非训练, 推理期用到
with torch.no_grad():
# 加载数据加载器得到里面的X图片数据和y(真实标签)
for X, y in dataloader:
# 将数据转到GPU
X, y = X.to(device), y.to(device)
# 将图片传入到模型当中就得到预测的值pred
pred = model(X)
# 计算预测值pred和真实值y的差距
test_loss += loss_fn(pred, y).item()
# 统计预测正确的个数(针对分类)
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= size
correct /= size
print(f"correct = {correct}, Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
return correct, test_loss
if __name__=='__main__':
batch_size = 20#设置批次大小,每次训练时用于更新模型的样本数量
# # 给训练集和测试集分别创建一个数据集加载器
train_data = LoadData("train.txt", True)#true为训练集
valid_data = LoadData("test.txt", False)#false为测试集
#批量加载数据num_workers并行工作线程数
train_dataloader = DataLoader(dataset=train_data, num_workers=4, pin_memory=True, batch_size=batch_size, shuffle=True)
valid_dataloader = DataLoader(dataset=valid_data, num_workers=4, pin_memory=True, batch_size=batch_size)
# 如果显卡可用,则用显卡进行训练
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
#创建一个ResNet-18模型实例
model = resnet18(num_classes=55)
model = model.to(device)
state_dict = torch.load(r"output/resnet18_no_pretrain_best.pth")
# print("state_dict = ",state_dict)
model.load_state_dict(state_dict)
# 定义损失函数,计算相差多少,交叉熵,
loss_fn = nn.CrossEntropyLoss()
# 定义优化器,随机梯度下降法
learning_rate = 1e-3
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
#设置训练总轮数初始化变量loss用于跟踪最低的平均损失值
epochs = 50
loss_ = 10
save_root = "output/"
for t in range(epochs):
print(f"Epoch {t + 1}\n-------------------------------")
time_start = time.time()
avg_loss = train(train_dataloader, model, loss_fn, optimizer, device)
time_end = time.time()
print(f"train time: {(time_end - time_start)}")
# (dataloader, model, loss_fn, device)jif
#调用 validate 函数进行验证集上的性能评估,计算验证集的准确率和损失
val_accuracy, val_loss = validate(valid_dataloader, model,loss_fn, device)
# 将训练和验证的结果写入文件写入数据
WriteData(save_root + "resnet18_no_pretrain.txt",
"epoch", t,#epoch数
"train_loss", avg_loss,#训练损失
"val_loss", val_loss,#验证损失
"val_accuracy", val_accuracy)#验证准确率
#如果当前epoch是5的倍数保存模型参数文件以便后续恢复或继续训练。
if t % 5 == 0:
torch.save(model.state_dict(), save_root + "resnet18_no_pretrain_epoch" + str(t) + "_loss_" + str(avg_loss) + ".pth")
#每个epoch都保存模型参数文件以便后续分析和恢复。
torch.save(model.state_dict(), save_root + "resnet18_no_pretrain_last.pth")
#如果当前epoch的平均损失小于 loss_则更新 loss_ 为当前损失值,并保存当前模型参数作为最佳模型。
if avg_loss < loss_:
loss_ = avg_loss
torch.save(model.state_dict(), save_root + "resnet18_no_pretrain_best.pth")
torch.cuda.empty_cache()

@ -1,77 +0,0 @@
'''
单图测试
'''
import torch
from torchvision.models import resnet18
from PIL import Image
import torchvision.transforms as transforms
import os
transform_BZ= transforms.Normalize(
mean=[0.46402064, 0.45047238, 0.37801373], # 取决于数据集
std=[0.2007732, 0.196271, 0.19854763]
)
def padding_black(img,img_size = 512): # 如果尺寸太小可以扩充
w, h = img.size
scale = img_size / max(w, h)
img_fg = img.resize([int(x) for x in [w * scale, h * scale]])
size_fg = img_fg.size
size_bg = img_size
img_bg = Image.new("RGB", (size_bg, size_bg))
img_bg.paste(img_fg, ((size_bg - size_fg[0]) // 2,
(size_bg - size_fg[1]) // 2))
img = img_bg
return img
if __name__=='__main__':
img_path = r'enhance_dataset/有害垃圾_药片/img_药片_7_vertical.jpg'
#创建了一个图像转换操作的组合,该组合将应用于输入图像。
#这些操作包括将图像调整大小为512x512像素将图像转换为张量
val_tf = transforms.Compose([ ##简单把图片压缩了变成Tensor模式
transforms.Resize(512),
transforms.ToTensor(),
transform_BZ # 标准化操作
])
# 如果显卡可用,则用显卡进行训练
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
finetune_net = resnet18(num_classes=55).to(device)
#创建ResNet-18深度学习模型
#分类成55个不同的类别
state_dict = torch.load(r"output/resnet18_no_pretrain_best.pth")
# print("state_dict = ",state_dict)
finetune_net.load_state_dict(state_dict)
#最后,这一行将模型设置为评估模式,这表示模型将在推理模式下运行,不进行梯度计算。
#这对于推断和预测任务非常有用,因为在这些情况下不需要计算梯度。模型在评估模式下运行时,通常更加高效。
finetune_net.eval()
with torch.no_grad():
# finetune_net.to(device)
img = Image.open(img_path) # 打开图片
img = img.convert('RGB') # 转换为RGB 格式
img = padding_black(img)
img = val_tf(img)
img_tensor = torch.unsqueeze(img, 0) # N,C,H,W, ; C,H,W
img_tensor = img_tensor.to(device)
result = finetune_net(img_tensor)
# print("result = ",result.argmax(1))
id = result.argmax(1).item()
file_list=[]
for a,b,c in os.walk("dataset"):
if len(b) != 0:
file_list = b
print("预测结果为:",file_list[id])

@ -1,135 +0,0 @@
'''
加载pytorch自带的模型从头训练自己的数据
'''
import time
import torch
from torch import nn
from torch.utils.data import DataLoader
from utils import LoadData,WriteData
from torchvision.models import resnet18, resnet34,resnet50, resnet101, resnet152 ,mobilenet_v2 # ResNet系列
def train(dataloader, model, loss_fn, optimizer,device):
size = len(dataloader.dataset)
avg_loss = 0
# 从数据加载器中读取batch一次读取多少张即批次数X(图片数据)y图片真实标签
for batch, (X, y) in enumerate(dataloader):#固定格式batch第几批数据不是批次大小Xy数值用括号
# print(size)
# 将数据存到显卡
X, y = X.to(device), y.to(device)
# 得到预测的结果pred
pred = model(X)
loss = loss_fn(pred, y)
avg_loss += loss
# 反向传播,更新模型参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每训练10次输出一次当前信息
if batch % 10 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
# 当一个epoch完了后返回平均 loss
avg_loss /= size
avg_loss = avg_loss.detach().cpu().numpy()
return avg_loss
def validate(dataloader, model, loss_fn, device):
size = len(dataloader.dataset)
# 将模型转为验证模式
model.eval()
# 初始化test_loss 和 correct 用来统计每次的误差
test_loss, correct = 0, 0
# 测试时模型参数不用更新所以no_gard()
# 非训练, 推理期用到
with torch.no_grad():
# 加载数据加载器得到里面的X图片数据和y(真实标签)
for X, y in dataloader:
# 将数据转到GPU
X, y = X.to(device), y.to(device)
# 将图片传入到模型当中就得到预测的值pred
pred = model(X)
# 计算预测值pred和真实值y的差距
test_loss += loss_fn(pred, y).item()
# 统计预测正确的个数(针对分类)
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= size
correct /= size
print(f"correct = {correct}, Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
return correct, test_loss
if __name__=='__main__':
batch_size = 32
# # 给训练集和测试集分别创建一个数据集加载器
train_data = LoadData("train.txt", True)
valid_data = LoadData("test.txt", False)
train_dataloader = DataLoader(dataset=train_data, num_workers=4, pin_memory=True, batch_size=batch_size, shuffle=True)
valid_dataloader = DataLoader(dataset=valid_data, num_workers=4, pin_memory=True, batch_size=batch_size)
# 如果显卡可用,则用显卡进行训练
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
finetune_net = resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 55)
nn.init.xavier_normal_(finetune_net.fc.weight)
parms_1x = [value for name, value in finetune_net.named_parameters()
if name not in ["fc.weight", "fc.bias"]]
# 最后一层10倍学习率
parms_10x = [value for name, value in finetune_net.named_parameters()
if name in ["fc.weight", "fc.bias"]]
finetune_net = finetune_net.to(device)
# 定义损失函数,计算相差多少,交叉熵,
loss_fn = nn.CrossEntropyLoss()
# 定义优化器,用来训练时候优化模型参数,随机梯度下降法
learning_rate = 1e-4
optimizer = torch.optim.Adam([
{
'params': parms_1x
},
{
'params': parms_10x,
'lr': learning_rate * 10
}], lr=learning_rate)
epochs = 50
loss_ = 10
save_root = "output/"
for t in range(epochs):
print(f"Epoch {t + 1}\n-------------------------------")
time_start = time.time()
avg_loss = train(train_dataloader, finetune_net, loss_fn, optimizer, device)
time_end = time.time()
print(f"train time: {(time_end - time_start)}")
val_accuracy, val_loss = validate(valid_dataloader, finetune_net,loss_fn, device)
# 写入数据
WriteData(save_root + "resnet18_e.txt",
"epoch", t,
"train_loss", avg_loss,
"val_loss", val_loss,
"val_accuracy", val_accuracy)
if t % 5 == 0:
torch.save(finetune_net.state_dict(), save_root + "resnet18_e_epoch" + str(t) + "_loss_" + str(avg_loss) + ".pth")
torch.save(finetune_net.state_dict(), save_root + "resnet18_e_last.pth")
if avg_loss < loss_:
loss_ = avg_loss
torch.save(finetune_net.state_dict(), save_root + "resnet18_e_best.pth")

@ -1,74 +0,0 @@
# -*-coding:utf-8-*-
from matplotlib import pyplot as plt
import numpy as np
def ReadData(data_loc):
epoch_list = []
train_loss_list = []
test_loss_list = []
test_accuracy_list = []
# open(data_loc,"r").readlines()
with open(data_loc, "r") as f:
linedata = f.readlines()
for line_i in linedata:
data = line_i.split('\t')
print("data = ", data)
epoch_i , train_loss_i,test_loss_i,test_accuracy_i =data[1], data[3],data[5],data[7]
epoch_list.append(int(epoch_i))
train_loss_list.append(float(train_loss_i))
test_loss_list.append(float(test_loss_i))
test_accuracy_list.append(float(test_accuracy_i))
# print(epoch_list)
# print(train_loss_list)
# print(test_loss_list)
# print(test_accuracy_list)
return epoch_list, train_loss_list ,test_loss_list,test_accuracy_list
def DrawLoss(train_loss_list,train_loss_list_2):
plt.style.use('dark_background')
plt.title("Loss")
plt.xlabel("epoch")
plt.ylabel("loss")
train_loss_list = train_loss_list[:10]
epoch_list = [i for i in range(len(train_loss_list))]
p1, = plt.plot(epoch_list, train_loss_list, linewidth=3)
p2, = plt.plot(epoch_list, train_loss_list_2, linewidth=3)
plt.legend([p1, p2], ["with pretrain", "no pretrain"])
plt.show()
def DrawAcc(train_loss_list,train_loss_list_2):
plt.style.use('dark_background')
plt.title("Accuracy")
plt.xlabel("epoch")
plt.ylabel("accuracy")
train_loss_list = train_loss_list[:10]
epoch_list = [i for i in range(len(train_loss_list))]
p1, = plt.plot(epoch_list, train_loss_list, linewidth=3)
p2, = plt.plot(epoch_list, train_loss_list_2, linewidth=3)
plt.legend([p1, p2], ["with pretrain", "no pretrain"])
plt.show()
if __name__ == '__main__':
data_1_loc = "output/resnet18.txt"
data_2_loc = "output/resnet18_no_pretrain.txt"
_, train_loss_list ,test_loss_list,test_accuracy_list = ReadData(data_1_loc)
_, train_loss_list_2 ,test_loss_list_2,test_accuracy_list_2 = ReadData(data_2_loc)
DrawLoss(train_loss_list,train_loss_list_2)
DrawAcc(test_accuracy_list,test_accuracy_list_2)

@ -1,75 +0,0 @@
import torch
from torch.utils.data import DataLoader
from utils import LoadData,WriteData
import torch.nn as nn
from torchvision.models import resnet18
from tqdm import tqdm
import os
import pandas as pd
def test(dataloader, model, device):
pred_list = []
# 将模型转为验证模式
model.eval()
# 测试时模型参数不用更新所以no_gard()
# 非训练, 推理期用到
with torch.no_grad():
# 加载数据加载器得到里面的X图片数据和y(真实标签)
for X, y in tqdm(dataloader):
# 将数据转到GPU
X, y = X.to(device), y.to(device)
# 将图片传入到模型当中就得到预测的值pred
pred = model(X)
pred_softmax = torch.softmax(pred, 1).cpu().numpy()
pred_list.append(pred_softmax.tolist()[0])
return pred_list
if __name__=='__main__':
batch_size = 1
# # 给训练集和测试集分别创建一个数据集加载器
test_data = LoadData("test.txt", False)
test_dataloader = DataLoader(dataset=test_data, num_workers=4, pin_memory=True, batch_size=batch_size)
# 如果显卡可用,则用显卡进行训练
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
model = resnet18(num_classes=55)
model.load_state_dict(torch.load("output/resnet18_e_best.pth"))
model.to(device)
# 定义损失函数,计算相差多少,交叉熵,
# loss_fn = nn.CrossEntropyLoss()
'''
获取结果
'''
# 获取模型输出
pred_list = test(test_dataloader, model,device)
print("pred_list = ", pred_list)
'''
获取文件夹列表
'''
file_name_list = []
data_root = r"enhance_dataset"
for a,b,c in os.walk(data_root):
if len(b) != 0:
print(b)
file_name_list = b
df_pred = pd.DataFrame(data=pred_list, columns=file_name_list)
print(df_pred)
df_pred.to_csv('pred_result.csv', encoding='gbk', index=False)

@ -1,78 +0,0 @@
from sklearn.metrics import * # pip install scikit-learn
import matplotlib.pyplot as plt # pip install matplotlib
import pandas as pd # pip install pandas
import os
'''
读取数据
需要读取模型输出的标签predict_label以及原本的标签true_label
'''
target_loc = "./test.txt" # 真实标签所在的文件
target_data = pd.read_csv(target_loc, sep="\t", names=["loc","type"])
true_label = [i for i in target_data["type"]]
predict_loc = "./pred_result.csv" # 3.ModelEvaluate.py生成的文件
predict_data = pd.read_csv(predict_loc,encoding="GBK")#,index_col=0)
predict_label = predict_data.to_numpy().argmax(axis=1)
predict_score = predict_data.to_numpy().max(axis=1)
'''
常用指标精度查准率召回率F1-Score
'''
# 精度,准确率, 预测正确的占所有样本种的比例
accuracy = accuracy_score(true_label, predict_label)
print("精度: ",accuracy)
# 查准率P准确率precision(查准率)=TP/(TP+FP)
precision = precision_score(true_label, predict_label, labels=None, pos_label=1, average='macro') # 'micro', 'macro', 'weighted'
print("查准率P: ",precision)
# 查全率R召回率原本为对的预测正确的比例recall(查全率)=TP/(TP+FN)
recall = recall_score(true_label, predict_label, average='macro') # 'micro', 'macro', 'weighted'
print("召回率: ",recall)
# F1-Score
f1 = f1_score(true_label, predict_label, average='macro') # 'micro', 'macro', 'weighted'
print("F1 Score: ",f1)
'''
混淆矩阵
'''
label_names = []
data_root = r"./enhance_dataset"
for a,b,c in os.walk(data_root):
if len(b) != 0:
print(b)
label_names = b
confusion = confusion_matrix(true_label, predict_label, labels=[i for i in range(len(label_names))])
plt.matshow(confusion, cmap=plt.cm.Oranges) # Greens, Blues, Oranges, Reds
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置中文字体
plt.rcParams["font.size"] = 8
plt.rcParams["axes.unicode_minus"] = False # 该语句解决图像中的“-”负号的乱码问题
plt.colorbar()
for i in range(len(confusion)):
for j in range(len(confusion)):
plt.annotate(confusion[j,i], xy=(i, j), horizontalalignment='center', verticalalignment='center')
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.xticks(range(len(label_names)), label_names,rotation=270)
plt.yticks(range(len(label_names)), label_names)
plt.title("Confusion Matrix")
plt.show()

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

@ -1,6 +1,5 @@
plugins {
id 'com.android.application'
id "org.sonarqube" version "3.5.0.2730"
}
android {
@ -9,7 +8,7 @@ android {
defaultConfig {
applicationId "com.example.myapplication"
minSdk 26
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"
@ -30,41 +29,18 @@ android {
buildFeatures {
viewBinding true
}
sourceSets{
main {
//jnilibsso
jniLibs.srcDirs = ['libs']
assets.srcDirs+=['src/main/com.example.myapplication/raw']
}
}
}
dependencies {
// implementation 'com.tencent.map:tencent-map-vector-sdk:4.3.5'
// implementation 'com.tencent.map.geolocation:TencentLocationSdk-openplatform:8.7.5.1'
implementation 'com.github.JediBurrell:customFloatingActionButton:-SNAPSHOT'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.tencent.map:tencent-map-nav-sdk:5.4.6.0'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'androidx.navigation:navigation-fragment:2.4.1'
implementation 'androidx.navigation:navigation-ui:2.4.1'
implementation files('libs\\tencent-mapsdk-android-official-release.5.2.1.18c8cd09.jar')
implementation files('libs\\poi-3.12-android-a.jar')
implementation files('libs\\poi-ooxml-schemas-3.12-20150511-a.jar')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -4,5 +4,5 @@
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Fri Sep 29 04:34:54 CST 2023
sdk.dir=F\:\\AndroidSDK\\AndroidSDK
#Mon Sep 25 09:53:48 CST 2023
sdk.dir=E\:\\Android_SDK

@ -1,39 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 通过GPS得到精确位置 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 通过网络得到粗略位置 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 访问网络,某些位置信息需要从网络服务器获取 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 访问WiFi状态需要WiFi信息用于网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 修改WiFi状态发起WiFi扫描, 需要WiFi信息用于网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!-- 访问网络状态, 检测网络的可用性,需要网络运营商相关信息用于网络定位 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 访问网络的变化, 需要某些信息用于网络定位 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!-- 蓝牙扫描权限 -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- 前台service权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- 后台定位权限 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<!-- A-GPS辅助定位权限方便GPS快速准确定位 -->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@ -42,39 +11,15 @@
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
<meta-data android:name="TencentMapSDK" android:value="3P5BZ-UWDK3-K5U34-RN5YR-3VQC6-XYBYX"/>
<activity android:name=".ui.index"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".BottomNavigiationActivity"
android:exported="true"
android:label="@string/title_activity_bottom_navigiation">
</activity>
<activity android:name=".ui.home.CameraPreview"
android:exported="true"
android:launchMode="standard"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.home.ResultActivity"
android:exported="true"
android:launchMode="standard"
></activity>
</application>
</manifest>

@ -1,6 +0,0 @@
projectKey=Test
serverUrl=http://localhost:9000
serverVersion=9.9.0.65466
dashboardUrl=http://localhost:9000/dashboard?id=Test
ceTaskId=AYu0FgJhk-ulwfDUJI5I
ceTaskUrl=http://localhost:9000/api/ce/task?id=AYu0FgJhk-ulwfDUJI5I

Binary file not shown.

@ -3,7 +3,6 @@ package com.example.myapplication;
import android.media.Image;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@ -12,7 +11,6 @@ import android.widget.ImageButton;
import com.example.myapplication.ui.Buttonfragments.RecycleGarbageFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
@ -21,7 +19,6 @@ import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.example.myapplication.databinding.BottomNavigiationBinding;
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
import java.util.List;
@ -31,16 +28,18 @@ public class BottomNavigiationActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// Log.d("wc","create");
super.onCreate(savedInstanceState);
binding = BottomNavigiationBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
this.getSupportActionBar().hide();
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications,R.id.navigation_quiz)
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
navView.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_bottom_navigiation);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(binding.navView, navController);
}
}

@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment;
import com.example.myapplication.R;
public class HazardGarbageFragment extends Fragment {//有害垃圾介绍
public class HazardGarbageFragment extends Fragment {
public HazardGarbageFragment() {
// Required empty public constructor

@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment;
import com.example.myapplication.R;
public class KitchenGarbageFragment extends Fragment {//厨余垃圾介绍
public class KitchenGarbageFragment extends Fragment {
public KitchenGarbageFragment() {
// Required empty public constructor

@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment;
import com.example.myapplication.R;
public class OtherGarbageFragment extends Fragment {//其他垃圾介绍
public class OtherGarbageFragment extends Fragment {
public OtherGarbageFragment() {
// Required empty public constructor

@ -9,11 +9,12 @@ import androidx.fragment.app.Fragment;
import com.example.myapplication.R;
public class RecycleGarbageFragment extends Fragment {//可回收垃圾介绍
public class RecycleGarbageFragment extends Fragment {
public RecycleGarbageFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

@ -1,88 +0,0 @@
package com.example.myapplication.ui.dashboard;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.myapplication.R;
import com.example.myapplication.databinding.FragmentDashboardBinding;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.tencent.lbssearch.TencentSearch;
import com.tencent.lbssearch.httpresponse.HttpResponseListener;
import com.tencent.lbssearch.object.param.WalkingParam;
import com.tencent.lbssearch.object.result.WalkingResultObject;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory;
import com.tencent.tencentmap.mapsdk.maps.TencentMapInitializer;
import com.tencent.tencentmap.mapsdk.maps.TextureMapView;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
public class MapActivity extends Fragment {
private TextureMapView mapView;
private FloatingActionButton currentPositioning;
private FloatingActionButton nearbyTrashBinChoose;
private FloatingActionButton navigation;
private FragmentDashboardBinding binding;
private MapPositioning controller;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
MapActivityViewModel dashboardViewModel = new ViewModelProvider(this).get(MapActivityViewModel.class);
TencentMapInitializer.setAgreePrivacy(true);
binding = FragmentDashboardBinding.inflate(inflater, container, false);
View root = binding.getRoot();
mapView = root.findViewById(R.id.mapview);
currentPositioning = root.findViewById(R.id.Get_Current_Location);
nearbyTrashBinChoose = root.findViewById(R.id.check_nearby_trash_cans);
navigation = root.findViewById(R.id.navigiation);
controller = new MapPositioning(mapView, binding,getActivity());
currentPositioning.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
controller.onClickCurrentPositioning();
}
});
nearbyTrashBinChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
controller.onClickNearbyTrashBinChoose();
}
});
navigation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
controller.onClickNavigation();
}
});
controller.startLocationUpdates();
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
controller.stopLocationUpdates();
mapView.onDestroy();
binding = null;
}
}

@ -1,19 +0,0 @@
package com.example.myapplication.ui.dashboard;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MapActivityViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public MapActivityViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is dashboard fragment");
}
public LiveData<String> getText() {
return mText;
}
}

@ -1,233 +0,0 @@
package com.example.myapplication.ui.dashboard;
import android.graphics.Color;
import android.view.View;
import android.widget.Toast;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
import com.example.myapplication.databinding.FragmentDashboardBinding;
import com.tencent.lbssearch.TencentSearch;
import com.tencent.lbssearch.httpresponse.HttpResponseListener;
import com.tencent.lbssearch.object.param.WalkingParam;
import com.tencent.lbssearch.object.result.WalkingResultObject;
import com.tencent.map.geolocation.TencentLocationManager;
import com.tencent.map.geolocation.TencentLocationRequest;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdate;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory;
import com.tencent.tencentmap.mapsdk.maps.TencentMap;
import com.tencent.tencentmap.mapsdk.maps.TextureMapView;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import com.tencent.tencentmap.mapsdk.maps.model.LatLngBounds;
import com.tencent.tencentmap.mapsdk.maps.model.Marker;
import com.tencent.tencentmap.mapsdk.maps.model.MarkerOptions;
import com.tencent.tencentmap.mapsdk.maps.model.PolylineOptions;
import java.util.ArrayList;
import java.util.List;
public class MapPositioning {
private TextureMapView mapView;
private TencentMap tencentMap;
private FragmentDashboardBinding binding;
private List<LatLng> TrashBin;
private FragmentActivity fragmentActivity;
static double currentLatitude;
static double currentLongitude;
TencentSearch tencentSearch;
WalkingParam walkingParam;
LatLng chooseTrashBin;
public float calculateDistance(LatLng start, LatLng end) {//计算所有标记垃圾桶与当前位置的距离
double earthRadius = 6371;
double lat1 = Math.toRadians(start.getLatitude());
double lon1 = Math.toRadians(start.getLongitude());
double lat2 = Math.toRadians(end.getLatitude());
double lon2 = Math.toRadians(end.getLongitude());
double deltaLat = lat2 - lat1;
double deltaLon = lon2 - lon1;
double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2)
+ Math.cos(lat1) * Math.cos(lat2)
* Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return (float) (earthRadius * c);
}
private HttpResponseListener<WalkingResultObject> httpResponseListener;
public MapPositioning(TextureMapView mapView, FragmentDashboardBinding binding,FragmentActivity activity) {//初始化,
this.mapView = mapView;
this.binding = binding;
tencentMap = mapView.getMap();
tencentMap.setMyLocationEnabled(true);
tencentMap.enableMultipleInfowindow(true);
fragmentActivity=activity;
TrashBin=new ArrayList<>();
TrashBin.add(new LatLng(39.111981,117.350131));//添加垃圾桶位置信息
TrashBin.add(new LatLng(39.112578,117.349414));
TrashBin.add(new LatLng(39.112062,117.349687));
TrashBin.add(new LatLng(39.1162,117.350954));
TrashBin.add(new LatLng(39.115949,117.351535));
TrashBin.add(new LatLng(39.115614,117.351487));
TrashBin.add(new LatLng(39.115767,117.351119));
tencentSearch=new TencentSearch(mapView.getContext());
httpResponseListener = new HttpResponseListener<WalkingResultObject>() {
@Override
public void onSuccess(int i, WalkingResultObject walkingResultObject) {
if(walkingParam==null)
{
return ;
}
for(WalkingResultObject.Route route:walkingResultObject.result.routes)
{
List<LatLng> polyline = route.polyline;
tencentMap.addPolyline(new PolylineOptions().addAll(polyline).width(5f).color(Color.RED));
}
}
@Override
public void onFailure(int i, String s, Throwable throwable) {
}
};
tencentMap.setOnMarkerClickListener(new TencentMap.OnMarkerClickListener() {//根据当前上一次的点击事件,判断是否为双击事件,如果是双击事件就进行导航
private long lastClickTime;
@Override
public boolean onMarkerClick(Marker marker) {
long clicktime=System.currentTimeMillis();
if(clicktime-lastClickTime<1000)
{
LatLng now = marker.getPosition();
walkingParam=new WalkingParam(new LatLng(currentLatitude,currentLongitude),now);
tencentSearch.getRoutePlan(walkingParam, httpResponseListener);
}
lastClickTime=clicktime;
return true;
}
});
}
public void onClickCurrentPositioning() {//发送请求,获取当前位置信息
String message = "当前位置:纬度:" + currentLatitude + ",经度:" + currentLongitude;
Toast.makeText(mapView.getContext(), message, Toast.LENGTH_SHORT).show();
tencentMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(currentLatitude,currentLongitude)));
}
public void onClickNearbyTrashBinChoose() {//显示附近的垃圾桶位置信息
long st=System.currentTimeMillis();
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for(LatLng trashBin:TrashBin)
{
tencentMap.addMarker(new MarkerOptions(trashBin));
}
builder.include(new LatLng(currentLatitude,currentLongitude));
for(LatLng trashBin:TrashBin)
{
builder.include(trashBin);
}
LatLngBounds bounds = builder.build();
int padding=100;
CameraUpdate cameraUpdate=CameraUpdateFactory.newLatLngBounds(bounds,padding);
tencentMap.moveCamera(cameraUpdate);
long ed=System.currentTimeMillis();
System.out.println(ed);
}
public void onClickNavigation() {//进行导航功能
double shortestDistance=Double.MAX_VALUE;
LatLng now = new LatLng(currentLatitude, currentLongitude);
for(LatLng trashBin:TrashBin)//获取所有垃圾桶位置信息并计算距离
{
double distance=calculateDistance(now,trashBin);
if(distance<shortestDistance)
{
shortestDistance=distance;
chooseTrashBin=trashBin;
}
}
walkingParam = new WalkingParam(now,chooseTrashBin);
tencentSearch.getRoutePlan(walkingParam,httpResponseListener);
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(now);
builder.include(chooseTrashBin);
LatLngBounds bounds = builder.build();
int padding=100;
CameraUpdate cameraUpdate=CameraUpdateFactory.newLatLngBounds(bounds,padding);
tencentMap.moveCamera(cameraUpdate);
}
public void startLocationUpdates() {//更新地图位置信息
TencentLocationManager mLocationManager=TencentLocationManager.getInstance(fragmentActivity,null);
mLocationManager.setCoordinateType(TencentLocationManager.COORDINATE_TYPE_GCJ02);
TencentLocationRequest request= TencentLocationRequest.create();
request.setRequestLevel(TencentLocationRequest.REQUEST_LEVEL_ADMIN_AREA);
MyLocationListener myLocationListener=new MyLocationListener(tencentMap,fragmentActivity);
request.setInterval(3000);
mLocationManager.requestLocationUpdates(request,myLocationListener,TencentLocationRequest.REQUEST_LEVEL_GEO);
}
public void stopLocationUpdates() {//停止地图位置信息控制
TencentLocationManager mLocationManager=TencentLocationManager.getInstance(fragmentActivity,null);
MyLocationListener myLocationListener=new MyLocationListener(tencentMap,fragmentActivity);
mLocationManager.removeUpdates(myLocationListener);
}
}

@ -1,133 +0,0 @@
package com.example.myapplication.ui.dashboard;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.fragment.app.FragmentActivity;
import com.tencent.map.geolocation.TencentLocation;
import com.tencent.map.geolocation.TencentLocationListener;
import com.tencent.tencentmap.mapsdk.maps.TencentMap;
import com.tencent.tencentmap.mapsdk.maps.TencentMapNavi;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import com.tencent.tencentmap.mapsdk.maps.model.Marker;
import com.tencent.tencentmap.mapsdk.maps.model.MarkerOptions;
public class MyLocationListener implements TencentLocationListener, SensorEventListener {
private final int TIME_SENSOR = 10;
private TencentMap tencentMap;
private Marker marker;
private FragmentActivity activity;
private long lastTime;
private static float mAngle;
private Sensor orientationSensor;
private SensorManager sensorManager;
public MyLocationListener(TencentMap tencentMap, FragmentActivity activity) {
this.tencentMap = tencentMap;
this.activity = activity;
this.lastTime = System.currentTimeMillis();
sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
sensorManager.registerListener(this, orientationSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onLocationChanged(TencentLocation location, int error, String reason) {//发送请求
if (error == TencentLocation.ERROR_OK) {
// 定位成功
double latitude = location.getLatitude();
double longitude = location.getLongitude();
MapPositioning.currentLatitude=latitude;
MapPositioning.currentLongitude=longitude;
Log.d("latitude", "onLocationChanged: "+latitude);
Log.d("longitude","onLocationChanged"+longitude);
LatLng latLng = new LatLng(latitude, longitude);
if (marker != null) {
marker.remove(); // 清除之前的标记
}
marker = tencentMap.addMarker(new MarkerOptions(latLng));
marker.setRotation(mAngle);// 自定义标记图标
} else {
// 处理定位失败的情况
Toast.makeText(activity, "定位失败:" + reason, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onStatusUpdate(String name, int status, String desc) {
// 处理位置提供者状态变化的情况
}
@Override
public void onGnssInfoChanged(Object o) {
}
@Override
public void onNmeaMsgChanged(String s) {
}
public static int getScreenRotationOnPhone(Context context) {//获取手机的角度信息
final Display display = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return -90;
}
return 0;
}
@Override
public void onSensorChanged(SensorEvent event) {//获取当前手机的方向
if (System.currentTimeMillis() - lastTime < TIME_SENSOR) {
return;
}
switch (event.sensor.getType()) {
case Sensor.TYPE_ORIENTATION: {
float x = event.values[0];
x += getScreenRotationOnPhone(activity);
x %= 360.0F;
if (x > 180.0F)
x -= 360.0F;
else if (x < -180.0F)
x += 360.0F;
if (Math.abs(mAngle - x) < 3.0f) {
break;
}
mAngle = Float.isNaN(x) ? 0 : x;
if (marker != null) {
marker.setRotation(mAngle);
}
lastTime = System.currentTimeMillis();
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}

@ -1,170 +0,0 @@
package com.example.myapplication.ui.home;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import com.example.myapplication.R;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
public class CameraPreview extends AppCompatActivity {
private static final int REQUEST_IMAGE_CAPTURE = 1;
private static final int REQUEST_PERMISSION_CAMERA = 2;
private ImageView imageView;
private File photoFile;
private String fileName;
public int flag;
FloatingActionButton capture,upload;
Bitmap bitmap;
private final static int RESULT_RECOGNITON=114514;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.capture);
this.getSupportActionBar().hide();
imageView = findViewById(R.id.show_photo);
capture=findViewById(R.id.recapture);
upload=findViewById(R.id.transmit);
capture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkCameraPermission();
}
});
upload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ImageUploader.setImageUploadCallback(new ImageUploadCallback() {//上传图片
public void onResultChanged(String result) {
int resultType = 0;
Log.d("resultss",result);
if ("可回收垃圾".equals(result)) {
resultType = 1;
} else if ("湿垃圾".equals(result)) {
resultType = 2;
} else if ("非生活垃圾".equals(result)||"干垃圾".equals(result)) {
resultType = 3;
}
else {
resultType=4;
}
Intent intent = new Intent(CameraPreview.this, ResultActivity.class);
intent.putExtra("result", resultType);
intent.putExtra("photoUrl", photoFile.getAbsolutePath());
startActivity(intent);
}
});
ImageUploader.imageUpload(photoFile.getAbsolutePath());
}
});
checkCameraPermission();
}
private void checkCameraPermission() {//检查相机权限
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CAMERA);
} else {
dispatchTakePictureIntent();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {//当接受相机返回结果
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_CAMERA) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED) {
dispatchTakePictureIntent();
} else {
Toast.makeText(this, "Camera permission denied.", Toast.LENGTH_SHORT).show();
}
}
}
private File createImageFile() throws IOException {
fileName= UUID.randomUUID().toString();
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File imageFile = File.createTempFile(fileName, ".jpg", storageDir);
return imageFile;
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
photoFile = createImageFile();
} catch (IOException ex) {
ex.printStackTrace();
}
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this, "com.example.myapplication.fileprovider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(photoFile);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
// 照片已成功保存到指定文件,将其添加到系统相册
galleryAddPic();
// 显示拍摄的照片
setPic();
}
else
{
finish();
}
}
private void setPic() {//显示对应的照片
// 获取保存的图片文件
if (photoFile != null) {
// 解析图片文件为 Bitmap
bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
// 设置到 ImageView 上显示
imageView.setImageBitmap(bitmap);
ByteArrayOutputStream stream =new ByteArrayOutputStream();
byte[] bytes = stream.toByteArray();
}
}
}

@ -1,59 +0,0 @@
package com.example.myapplication.ui.home;
import androidx.fragment.app.FragmentManager;
import com.example.myapplication.R;
import com.example.myapplication.ui.Buttonfragments.HazardGarbageFragment;
import com.example.myapplication.ui.Buttonfragments.KitchenGarbageFragment;
import com.example.myapplication.ui.Buttonfragments.OtherGarbageFragment;
import com.example.myapplication.ui.Buttonfragments.RecycleGarbageFragment;
public class GarbageRecognition {
private static GarbageRecognition instance;
private GarbageRecognitionActivity fragment;
private GarbageRecognition() {}
public static GarbageRecognition getInstance() {
if (instance == null) {
instance = new GarbageRecognition();
}
return instance;
}
public void setFragment(GarbageRecognitionActivity fragment) {
this.fragment = fragment;
}
public void onRecyclableGarbageButtonClick() {//转化到可回收垃圾的介绍界面
FragmentManager fragmentManager = fragment.getParentFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_container, new RecycleGarbageFragment()).commit();
fragment.clearTextUnderLineColor(fragment.flag);
fragment.setTextUnderLineColor("可回收垃圾", fragment.recycleText);
fragment.flag = 0;
}
public void onKitchenGarbageButtonClick() {//转化到厨余垃圾界面
FragmentManager fragmentManager = fragment.getParentFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_container, new KitchenGarbageFragment()).commit();
fragment.clearTextUnderLineColor(fragment.flag);
fragment.setTextUnderLineColor("厨余垃圾", fragment.kitchenText);
fragment.flag = 1;
}
public void onOtherGarbageButtonClick() {//转缓到其他垃圾的介绍界面
FragmentManager fragmentManager = fragment.getParentFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_container, new OtherGarbageFragment()).commit();
fragment.clearTextUnderLineColor(fragment.flag);
fragment.setTextUnderLineColor("其他垃圾", fragment.otherGarbageText);
fragment.flag = 2;
}
public void onHazardGarbageButtonClick() {//转化到有害垃圾的界面
FragmentManager fragmentManager = fragment.getParentFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_container, new HazardGarbageFragment()).commit();
fragment.clearTextUnderLineColor(fragment.flag);
fragment.setTextUnderLineColor("有害垃圾", fragment.hazardText);
fragment.flag = 3;
}
}

@ -1,119 +0,0 @@
package com.example.myapplication.ui.home;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.example.myapplication.R;
import com.example.myapplication.databinding.FragmentHomeBinding;
public class GarbageRecognitionActivity extends Fragment {
private ImageButton recyclableGarbageButton;
private ImageButton kitchenGarbageButton;
private ImageButton otherGarbageButton;
private ImageButton hazardGarbageButton;
private FragmentHomeBinding binding;
private ImageButton captureButton;
public TextView recycleText;
public TextView kitchenText;
public TextView otherGarbageText;
public TextView hazardText;
private SpannableString spannableString;
public int flag=0;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentHomeBinding.inflate(inflater, container, false);
View root = binding.getRoot();
recyclableGarbageButton = root.findViewById(R.id.recycle);
kitchenGarbageButton = root.findViewById(R.id.kitchen_garbage);
otherGarbageButton = root.findViewById(R.id.other_garbage);
hazardGarbageButton = root.findViewById(R.id.hazardous_waste);
captureButton = root.findViewById(R.id.capture);
recycleText = root.findViewById(R.id.recycle_text);
kitchenText = root.findViewById(R.id.kitchen_text);
otherGarbageText = root.findViewById(R.id.other_garbage_text);
hazardText = root.findViewById(R.id.hazardous_waste_text);
recyclableGarbageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
GarbageRecognition.getInstance().setFragment(GarbageRecognitionActivity.this);
GarbageRecognition.getInstance().onRecyclableGarbageButtonClick();
}
});
kitchenGarbageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
GarbageRecognition.getInstance().setFragment(GarbageRecognitionActivity.this);
GarbageRecognition.getInstance().onKitchenGarbageButtonClick();
}
});
otherGarbageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
GarbageRecognition.getInstance().setFragment(GarbageRecognitionActivity.this);
GarbageRecognition.getInstance().onOtherGarbageButtonClick();
}
});
hazardGarbageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
GarbageRecognition.getInstance().setFragment(GarbageRecognitionActivity.this);
GarbageRecognition.getInstance().onHazardGarbageButtonClick();
}
});
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), CameraPreview.class);
startActivity(intent);
}
});
recyclableGarbageButton.performClick();
return root;
}
public void setTextUnderLineColor(String text,TextView curText)//设置文本下划线,提示用户目前查看的是哪一个垃圾分类介绍信息
{
clearTextUnderLineColor(flag);
spannableString = new SpannableString(text);
UnderlineSpan underlineSpan = new UnderlineSpan();
spannableString.setSpan(underlineSpan,0,text.length(),0);
ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.rgb(3,169,244));
spannableString.setSpan(colorSpan,0,text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
curText.setText(spannableString);
}
public void clearTextUnderLineColor(int flag)//清空之前选中的按钮选项
{
switch (flag)
{
case 0:
recycleText.setText("可回收垃圾");
case 1:
kitchenText.setText("厨余垃圾");
case 2:
otherGarbageText.setText("其他垃圾");
case 3:
hazardText.setText("有害垃圾");
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

@ -1,19 +0,0 @@
package com.example.myapplication.ui.home;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class GarbageRecognitionActivityViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public GarbageRecognitionActivityViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is home fragment");
}
public LiveData<String> getText() {
return mText;
}
}

@ -1,5 +0,0 @@
package com.example.myapplication.ui.home;
public interface ImageUploadCallback {
void onResultChanged(String newResult);
}

@ -1,118 +0,0 @@
package com.example.myapplication.ui.home;
import android.util.Log;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ImageUploader {
private static String result;
private static ImageUploadCallback callback;
public static void setImageUploadCallback(ImageUploadCallback cb) {
callback = cb;
}
private static void notifyCallback() {
Log.d("aaaaaaa", "notifyCallback: ");
if (callback != null) {
callback.onResultChanged(result);
}
}
// 在获取到上传结果时调用该方法
private static void setResult(String newResult) {
result = newResult;
notifyCallback();
}
public static void imageUpload(String imagePath) {//前后端交互代码
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<Void> uploadTask = executorService.submit(() -> {
try {
String uploadUrl = "http://192.168.203.243:5000/upload_image"; // 替换为你的Flask服务器URL
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
System.out.println("Image file not found.");
return null;
}
URL url = new URL(uploadUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法为POST
connection.setRequestMethod("POST");
connection.setDoOutput(true);
// 构建请求体
String boundary = "*****";
String lineEnd = "\r\n";
String twoHyphens = "--";
String charset = "UTF-8";
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + imageFile.getName() + "\"" + lineEnd);
dos.writeBytes("Content-Type: image/jpeg" + lineEnd);
dos.writeBytes(lineEnd);
FileInputStream fileInputStream = new FileInputStream(imageFile);
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
Log.d("s1", "3 ");
// 发送请求并获取响应
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 请求成功
InputStream inputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line=reader.readLine();
Log.d("s1", line);
setResult(line);
inputStream.close();
} else {
Log.d("s1", "2 ");
// 请求失败
System.out.println("HTTP POST request failed with response code: " + responseCode);
}
fileInputStream.close();
dos.flush();
dos.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
});
// 等待上传任务完成
try {
uploadTask.get();
} catch (Exception e) {
e.printStackTrace();
}
// 关闭线程池
executorService.shutdown();
}
}

@ -1,57 +0,0 @@
package com.example.myapplication.ui.home;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;
import com.example.myapplication.R;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
public class ResultActivity extends AppCompatActivity {
private ImageView photo;
@Override
protected void onCreate(Bundle savedInstanceState) {//在后端发送数据后,跳转到对应的结果界面
super.onCreate(savedInstanceState);
this.getSupportActionBar().hide();
int resultType=getIntent().getIntExtra("result",1);
String photoFile =getIntent().getStringExtra("photoUrl") ;
Bitmap bitmap = BitmapFactory.decodeFile(photoFile);
switch (resultType)
{
case 1:
setContentView(R.layout.sonofrecycle_garbage);
break;
case 2:
setContentView(R.layout.sonofkitchen_garbage);
break;
case 3:
setContentView(R.layout.sonofother_garbage);
break;
case 4:
setContentView(R.layout.sonofhazard_garbage);
break;
}
photo=findViewById(R.id.picture);
photo.setImageBitmap(bitmap);
}
}

@ -1,34 +0,0 @@
package com.example.myapplication.ui;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import androidx.appcompat.app.AppCompatActivity;
import com.example.myapplication.BottomNavigiationActivity;
import com.example.myapplication.R;
import com.example.myapplication.ui.home.GarbageRecognitionActivity;
public class index extends AppCompatActivity {
private static final long SPLASH_DELAY = 800; // 延迟时间,单位为毫秒,启动界面
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getSupportActionBar().hide();
// 设置启动页布局文件
setContentView(R.layout.launch_screen);
// 延迟跳转到主界面
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(index.this, BottomNavigiationActivity.class);
startActivity(intent);
finish(); // 销毁当前活动,防止用户返回到启动页
}
}, SPLASH_DELAY);
}
}

@ -1,125 +0,0 @@
package com.example.myapplication.ui.notifications;
import android.util.Log;
import android.widget.Toast;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FeedbackUploader {//反馈信息与后端进行交互
public static void submitFeedback(UserFeedbackActivity userFeedbackActivity, String imagePath,String additionalString) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Toast toast = new Toast(userFeedbackActivity.getActivity());
Future<Void> uploadTask = executorService.submit(() -> {
try {
Log.d("s2","t1");
String uploadImageUrl = "http://192.168.203.243:5000/upload_image"; // 替换为图片上传的URL
String uploadStringUrl = "http://192.168.203.243:5000/upload_text"; // 替换为字符串上传的URL
Log.d("s2","t2");
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
Log.d("s2","t3");
System.out.println("Image file not found.");
return null;
}
Log.d("s2","t1");
// 发送图片
URL imageUrl = new URL(uploadImageUrl);
HttpURLConnection imageConnection = (HttpURLConnection) imageUrl.openConnection();
imageConnection.setRequestMethod("POST");
imageConnection.setDoOutput(true);
// 构建请求体
String boundary = "*****";
String lineEnd = "\r\n";
String twoHyphens = "--";
imageConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
DataOutputStream imageDos = new DataOutputStream(imageConnection.getOutputStream());
imageDos.writeBytes(twoHyphens + boundary + lineEnd);
imageDos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + imageFile.getName() + "\"" + lineEnd);
imageDos.writeBytes("Content-Type: image/jpeg" + lineEnd);
imageDos.writeBytes(lineEnd);
FileInputStream imageInputStream = new FileInputStream(imageFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = imageInputStream.read(buffer)) != -1) {
imageDos.write(buffer, 0, bytesRead);
}
imageDos.writeBytes(lineEnd);
imageDos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
Log.d("s2","t1");
// 发送图片请求并获取响应
int imageResponseCode = imageConnection.getResponseCode();
if (imageResponseCode == HttpURLConnection.HTTP_OK) {
// 图片上传成功
// System.out.println("Image uploaded successfully.");
InputStream inputStream = imageConnection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
line=reader.readLine();
inputStream.close();
Log.d("s2","t2");
// 发送字符串
URL urlString = new URL(uploadStringUrl);
HttpURLConnection stringConnection = (HttpURLConnection) urlString.openConnection();
stringConnection.setRequestMethod("POST");
stringConnection.setDoOutput(true);
stringConnection.setRequestProperty("Content-Type", "text/plain");
OutputStream stringOs = stringConnection.getOutputStream();
stringOs.write(additionalString.getBytes("UTF-8"));
stringOs.flush();
stringOs.close();
// 获取字符串上传响应
int stringResponseCode = stringConnection.getResponseCode();
if (stringResponseCode == HttpURLConnection.HTTP_OK) {
Log.d("s2","t3");
// 字符串上传成功
InputStream inputStream2 = stringConnection.getInputStream();
BufferedReader reader2 = new BufferedReader(new InputStreamReader(inputStream2));
while ((line = reader2.readLine()) != null) {
System.out.println(line);
}
inputStream2.close();
toast.setText("图片上传成功!");
} else {
toast.setText("图片上传失败");
// 字符串上传失败
System.out.println("String upload failed with response code: " + stringResponseCode);
}
} else {
// 图片上传失败
toast.setText("图片上传失败");
System.out.println("Image upload failed with response code: " + imageResponseCode);
}
imageInputStream.close();
imageDos.flush();
imageDos.close();
} catch (Exception e) {
e.printStackTrace();
}finally {
toast.show();
}
return null;
});
// 等待上传任务完成
try {
uploadTask.get();
} catch (Exception e) {
e.printStackTrace();
}
// 关闭线程池
executorService.shutdown();
}
}

@ -1,100 +0,0 @@
package com.example.myapplication.ui.notifications;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
public class UserFeedback {
public UserFeedbackActivity userFeedbackActivity;
public UserFeedback(UserFeedbackActivity userFeedbackActivity) {
this.userFeedbackActivity = userFeedbackActivity;
}
public void resetAll()//清空所有按钮内容
{
userFeedbackActivity.editText.setText("");
userFeedbackActivity.userExperience.setChecked(false);
userFeedbackActivity.positiveRecommendation.setChecked(false);
userFeedbackActivity.otherIssues.setChecked(false);
userFeedbackActivity.classificationExpansion.setChecked(false);
userFeedbackActivity.functionalRecommendations.setChecked(false);
userFeedbackActivity.identifyDeviations.setChecked(false);
}
public String getRealPathFromURI(Uri contentUri) {//获取对应图片的URI
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = userFeedbackActivity.getContext().getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
public void submitFeedback(Uri uri)//提交反馈
{
String feedback=recordFeedback();
FeedbackUploader.submitFeedback(userFeedbackActivity,getRealPathFromURI(uri),feedback);
}
public String recordFeedback()//格式化字符串方便与服务端进行通信格式为100011|文本信息,前面六位依次对应用户体验、识别偏差、功能建议、分类扩充、其他问题、好评推荐,|是分隔符,然后是文本数据即用户提交的数据
{
StringBuilder sb = new StringBuilder();
if(userFeedbackActivity.positiveRecommendation.isChecked())
{
sb.append('1');
}
else
{
sb.append('0');
}
if(userFeedbackActivity.otherIssues.isChecked())
{
sb.append('1');
}
else
{
sb.append('0');
}
if(userFeedbackActivity.classificationExpansion.isChecked())
{
sb.append('1');
}
else
{
sb.append('0');
}
if(userFeedbackActivity.functionalRecommendations.isChecked())
{
sb.append('1');
}
else
{
sb.append('0');
}
if(userFeedbackActivity.identifyDeviations.isChecked())
{
sb.append('1');
}
else
{
sb.append('0');
}
if(userFeedbackActivity.userExperience.isChecked())
{
sb.append('1');
}
else
{
sb.append('0');
}
String contentEditText=userFeedbackActivity.editText.getText().toString();
sb.append('|');
return sb.toString()+contentEditText;
}
}

@ -1,124 +0,0 @@
package com.example.myapplication.ui.notifications;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.myapplication.R;
import com.example.myapplication.databinding.FragmentNotificationsBinding;
import com.example.myapplication.ui.home.ImageUploader;
import com.google.android.material.checkbox.MaterialCheckBox;
public class UserFeedbackActivity extends Fragment {
private FragmentNotificationsBinding binding;
private ImageButton buttonSelectImage;
public EditText editText;
private Button submit,reset;
private UserFeedback userFeedback;
private Uri uri;
public MaterialCheckBox userExperience,identifyDeviations,functionalRecommendations,classificationExpansion,otherIssues,positiveRecommendation;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
UserFeedbackViewModel notificationsViewModel =
new ViewModelProvider(this).get(UserFeedbackViewModel.class);
userFeedback = new UserFeedback(this);
binding = FragmentNotificationsBinding.inflate(inflater, container, false);
View root = binding.getRoot();
editText = root.findViewById(R.id.input_feedback);
buttonSelectImage = root.findViewById(R.id.btn_select_image);
userExperience=root.findViewById(R.id.user_experience);
identifyDeviations=root.findViewById(R.id.identify_deviations);
functionalRecommendations = root.findViewById(R.id.functional_recommendations);
classificationExpansion = root.findViewById(R.id.classification_expansion);
otherIssues = root.findViewById(R.id.other_issues);
positiveRecommendation = root.findViewById(R.id.positive_recommendation);
submit = root.findViewById(R.id.submit);
reset = root.findViewById(R.id.reset);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
editText.setCursorVisible(false);
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if(editable != null&& editable.toString().length()>0)
{
editText.setCursorVisible(true);
editText.setGravity(Gravity.START);
}
else
{
editText.setGravity(Gravity.CENTER);
}
}
});
buttonSelectImage.setOnClickListener(new View.OnClickListener() {//跳转到相册界面
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_PICK,null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(intent,2);
}
});
submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userFeedback.submitFeedback(uri);
}
});
reset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userFeedback.resetAll();
}
});
return root;
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {//获取用户选择的相册的图片
if(resultCode==-1)
{
if(data!=null)
{
uri = data.getData();
buttonSelectImage.setImageURI(uri);
}
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

@ -1,19 +0,0 @@
package com.example.myapplication.ui.notifications;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class UserFeedbackViewModel extends ViewModel {
private final MutableLiveData<String> mText;
public UserFeedbackViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is notifications fragment");
}
public LiveData<String> getText() {
return mText;
}
}

@ -1,98 +0,0 @@
package com.example.myapplication.ui.quiz;
import android.graphics.Color;
import android.media.session.MediaSession;
import android.widget.MultiAutoCompleteTextView;
import android.widget.Toast;
import androidx.fragment.app.FragmentActivity;
import com.example.myapplication.R;
import com.example.myapplication.ui.tools.Problem;
import java.io.FileInputStream;
import java.io.IOException;
public class GarbageQuiz {
private Problem problemTool,analysisTool;//问题分析和分析分析的类对象
private GarbageQuizActivity fragment;//对应的界面
GarbageQuiz(GarbageQuizActivity fragmentActivity) throws IOException {
this.fragment=fragmentActivity;
problemTool = new Problem(fragment.getResources().openRawResource(R.raw.question));
analysisTool = new Problem(fragment.getResources().openRawResource(R.raw.answer));
}
void clearOptionColor()//清空之前活动的选项
{
fragment.aButton.setTextColor(Color.BLACK);
fragment.bButton.setTextColor(Color.BLACK);
fragment.cButton.setTextColor(Color.BLACK);
fragment.dButton.setTextColor(Color.BLACK);
}
public void chooseAOption()//选中A选项下面依次是选B、C、D选中后清空之前的选项文本颜色对应的选项文本颜色变为绿色
{
String answer = analysisTool.getAnswer(problemTool.getNow());
fragment.analysisTextView.setText(answer);
clearOptionColor();
fragment.aButton.setTextColor(Color.rgb(177,247,206));
}
public void chooseBOption()
{
String answer = analysisTool.getAnswer(problemTool.getNow());
fragment.analysisTextView.setText(answer);
clearOptionColor();
fragment.bButton.setTextColor(Color.rgb(177,247,206));
}
public void chooseCOption()
{
String answer = analysisTool.getAnswer(problemTool.getNow());
fragment.analysisTextView.setText(answer);
clearOptionColor();
fragment.cButton.setTextColor(Color.rgb(177,247,206));
}
public void chooseDOption()
{
String answer = analysisTool.getAnswer(problemTool.getNow());
fragment.analysisTextView.setText(answer);
clearOptionColor();
fragment.dButton.setTextColor(Color.rgb(177,247,206));
}
public void getLastQuestion()//获取前一个问题,如果是第一个问题,提示用户
{
clearOptionColor();
fragment.analysisTextView.setText("");
String[] strings = problemTool.getPreQuestion();
if (strings == null) {
Toast.makeText(this.fragment.getActivity(), "这已经是第一个问题啦", Toast.LENGTH_SHORT).show();
return;
}
fragment.question.setText(strings[0]);
fragment.aButton.setText(strings[1]);
fragment.bButton.setText(strings[2]);
fragment.cButton.setText(strings[3]);
fragment.dButton.setText(strings[4]);
}
public void getNextQuestion()//获取后一个问题,假如是最后一个问题,提示用户
{
clearOptionColor();
fragment.analysisTextView.setText("");
String[] strings = problemTool.getNextQuestion();
if (strings == null) {
Toast.makeText(this.fragment.getActivity(), "这已经是最后一个问题啦", Toast.LENGTH_SHORT).show();
return;
}
fragment.question.setText(strings[0]);
fragment.aButton.setText(strings[1]);
fragment.bButton.setText(strings[2]);
fragment.cButton.setText(strings[3]);
fragment.dButton.setText(strings[4]);
}
}

@ -1,94 +0,0 @@
package com.example.myapplication.ui.quiz;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import com.example.myapplication.R;
import com.example.myapplication.databinding.GarbageQuizBinding;
import com.example.myapplication.ui.home.GarbageRecognition;
import com.example.myapplication.ui.home.GarbageRecognitionActivityViewModel;
import com.example.myapplication.ui.notifications.UserFeedbackViewModel;
import java.io.IOException;
public class GarbageQuizActivity extends Fragment {
private GarbageQuizBinding binding;
public Button aButton,bButton,cButton,dButton;
private ImageButton preQuestionButton,nextQuestionButton;
private GarbageQuiz garbageQuiz;
public TextView question,analysisTextView;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
com.example.myapplication.ui.newthing.GarbageQuizViewModel notificationsViewModel =
new ViewModelProvider(this).get(com.example.myapplication.ui.newthing.GarbageQuizViewModel.class);
binding = GarbageQuizBinding.inflate(inflater,container,false);
View root = binding.getRoot();
aButton = root.findViewById(R.id.a_option);
bButton = root.findViewById(R.id.b_option);
cButton = root.findViewById(R.id.c_option);
dButton = root.findViewById(R.id.d_option);
question = root.findViewById(R.id.question);
analysisTextView = root.findViewById(R.id.analysisTextView);
preQuestionButton = root.findViewById(R.id.pre_question);
nextQuestionButton = root.findViewById(R.id.next_question);
try {
garbageQuiz =new GarbageQuiz(this);
} catch (IOException e) {
throw new RuntimeException(e);
}
aButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
garbageQuiz.chooseAOption();
}
});
bButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
garbageQuiz.chooseBOption();
}
});
cButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
garbageQuiz.chooseCOption();
}
});
dButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
garbageQuiz.chooseDOption();
}
});
preQuestionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
garbageQuiz.getLastQuestion();
}
});
nextQuestionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
garbageQuiz.getNextQuestion();
}
});
nextQuestionButton.performClick();
return root;
}
}

@ -1,19 +0,0 @@
package com.example.myapplication.ui.newthing;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class GarbageQuizViewModel extends ViewModel {
private MutableLiveData<String> mText;
public GarbageQuizViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is new fragment");//根据自己喜欢放界面的测试文字
}
public LiveData<String> getText() {
return mText;
}
}

@ -1,107 +0,0 @@
package com.example.myapplication.ui.tools;
import android.util.Log;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Problem {
private XSSFWorkbook workbook;
private int start;
private int end;
private int sz;
private int now=-1;
private boolean flag=true;
private ArrayList<String []>question;//存储对应的问题
private ArrayList<Integer> rowNum;//存储目前问题对应的xlsx行数
Sheet sheet;
public int getNow()
{
return rowNum.get(now);
}
public Problem(InputStream file) throws IOException {//打开res库中的xlsx读取对应的图库和解析
rowNum = new ArrayList<>();
try
{
workbook = new XSSFWorkbook(file);
sheet = workbook.getSheetAt(0);
sz = sheet.getPhysicalNumberOfRows();
Random random = new Random();
int randomNumber = random.nextInt(sz);
question = new ArrayList<>();
start=end=randomNumber;
int i;
int tmp=sz;
for(i=start;tmp!=0;tmp--,i++)
{
rowNum.add(i%sz);
Row row = sheet.getRow((i)%sz);
Cell cell = row.getCell(1);
if(cell != null)
{
String cellValue = cell.getStringCellValue();
cellValue=cellValue.replace(""," ");
String[] split = cellValue.split(" ");
question.add(split);
}
}
}catch (Exception e)
{
e.printStackTrace();
System.out.println("读取文件失败");
}
}
public void close() throws IOException {
workbook.close();
}
public String[] getPreQuestion()//获取前一个问题
{
if(now-1>=0)return question.get(--now);
else return null;
}
public String[] getNextQuestion()//获取后一个问题
{
if(now+1<question.size())return question.get(++now);
return null;
}
public String getAnswer(int row)//获取对应行的解析
{
Row nrow = sheet.getRow(row);
Cell cell = nrow.getCell(1);
Cell cell1 = nrow.getCell(2);
if(cell != null)
{
String cellValue = cell.getStringCellValue();
if(cell1 != null)
{
cellValue+=":";
cellValue+=cell1.getStringCellValue();
}
return cellValue;
}
return null;
}
}

@ -1 +0,0 @@
sonar-scanner.bat -D"sonar.projectKey=tsq" -D"sonar.sources=User" -D"sonar.host.url=http://localhost:9000" -D"sonar.login=sqp_cfe53f4667e9c83129469f7a698d2f74f5ef73ad"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

@ -1,4 +0,0 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/blue" />
<item android:color="@color/grey"/>
</selector>

@ -1,28 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle" >
<!-- 填充的颜色 -->
<solid android:color="@color/white"></solid>
<!-- 设置按钮的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="1dip" />
<!-- stroke 设置边框显示 -->
<!-- paddingButton里面的文字与Button边界的间隔 -->
<padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle" >
<!-- 填充的颜色 -->
<solid android:color="@color/grey"></solid>
<!-- 设置按钮的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="1dip" />
<!-- stroke 设置边框显示 -->
<!-- paddingButton里面的文字与Button边界的间隔 -->
<padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp" />
</shape>
<color android:color="@color/grey" /> <!-- 点击时的背景颜色 -->
</item>
<item>
<color android:color="#FFFFFF" /> <!-- 默认状态下的背景颜色 -->
</item>
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

@ -1,4 +0,0 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="23dp"/> <!-- 设置圆角半径,根据需要调整数值 -->
<solid android:color="@color/white"></solid>
</shape>

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle" >
<!-- 填充的颜色 -->
<solid android:color="@color/grey"></solid>
<!-- 设置按钮的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="10dip" />
<!-- paddingButton里面的文字与Button边界的间隔 -->
<padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp" />
</shape>
</item>
<item android:state_pressed="false">
<shape android:shape="rectangle" >
<!-- 填充的颜色 -->
<solid android:color="@color/blue"></solid>
<!-- 设置按钮的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="10dip" />
<!-- stroke 设置边框显示 -->
<stroke
android:dashGap="0dp"
android:width="1dp"
android:color="@color/grey" />
<!-- paddingButton里面的文字与Button边界的间隔 -->
<padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp" />
</shape>
</item>
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
</shape>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save