8位RGB图像,例(255,255,255),转二值图像(灰度图像)0和255
python
# 8位rgb转二值图
import cv2
import glob
from tqdm import tqdm
import os
all_inputs = glob.glob(r'./output/*.png')
output_pth = r'./gray_result'
if not os.path.exists(output_pth):
os.makedirs(output_pth)
for i in tqdm(range(len(all_inputs))):
path = all_inputs[i]
# 以灰度模式直接读取图像(即使原图是彩色,也会被转成单通道)
gray_img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
full_filename = os.path.basename(path)
outpth = os.path.join(output_pth, full_filename)
# 保存灰度图像
cv2.imwrite(outpth, gray_img)
# 查看形状
# print(gray_img.shape) # (height, width)
精度指标计算方式一
python
# 变化检测数据精度计算
import numpy as np
import glob
from PIL import Image
from sklearn.metrics import confusion_matrix,cohen_kappa_score
from sklearn.metrics import f1_score
from tqdm import tqdm
def mean_iou(input, target, classes = 2):
""" compute the value of mean iou
:param input: 2d array, int, prediction
:param target: 2d array, int, ground truth
:param classes: int, the number of class
:return:
miou: float, the value of miou
"""
miou = 0
for i in range(classes):
intersection = np.logical_and(target == i, input == i)
# print(intersection.any())
union = np.logical_or(target == i, input == i)
print(union)
temp = np.sum(intersection) / np.sum(union)
miou += temp
return miou/classes
def compute_f1(prediction, target):
"""
:param prediction: 2d array, int,
estimated targets as returned by a classifier
:param target: 2d array, int,
ground truth
:return:
f1: float
"""
prediction.tolist(), target.tolist()
img, target = np.array(prediction).flatten(), np.array(target).flatten()
f1 = f1_score(y_true=target, y_pred=img, average='micro')
return f1
def compute_kappa(prediction, target):
"""
:param prediction: 2d array, int,
estimated targets as returned by a classifier
:param target: 2d array, int,
ground truth
:return:
kappa: float
"""
prediction.tolist(), target.tolist()
img, target = np.array(prediction).flatten(), np.array(target).flatten()
kappa = cohen_kappa_score(target, img)
return kappa
def calculateTP(GT, PRE, size):
TP = 0
for y in range(0, size):
for x in range(0, size):
if GT[y, x].any() == 255 and PRE[y, x].any() == 255:
TP += 1
else:
continue
return TP
def calculateTN(GT, PRE, size):
TN = 0
for y in range(0,size):
for x in range(0,size):
if GT[y,x].any() == 0 and PRE[y,x].any() == 0:
TN += 1
else:
continue
return TN
def calculateFP(GT, PRE, size):
FP = 0
for y in range(0,size):
for x in range(0,size):
if GT[y,x].any() == 0 and PRE[y,x].any() == 255:
FP+=1
else:
continue
return FP
def calculateFN(GT,PRE, size):
FN = 0
for y in range(0,size):
for x in range(0,size):
if GT[y,x].any() == 255 and PRE[y,x].any() == 0:
FN += 1
else:
continue
return FN
# 标签
all_targets = glob.glob(r'S2looking/标签label/*.png')
# 输入文件
all_inputs = glob.glob(r'/Eval_CD/output/*.png') # 读取所有图像文件
# 文件大小
img_size = 1024
sum_mean_IoU = 0
sum_F1 = 0
sum_kappa = 0
TP_sum = 0
TN_sum = 0
FP_sum = 0
FN_sum = 0
for i in tqdm(range(len(all_inputs))):
target = all_targets[i]
input = all_inputs[i]
# print(target)
target = Image.open(target)
#target = target.convert('L')
target = np.array(target) # 将pillow对象转换为np数据
input = Image.open(input)
input= np.array(input)
TP = calculateTP(target, input, img_size)
TN = calculateTN(target, input, img_size)
FP = calculateFP(target, input, img_size)
FN = calculateFN(target, input, img_size)
TP_sum += TP
TN_sum += TN
FP_sum += FP
FN_sum += FN
presion = TP_sum / (TP_sum + FP_sum)
recall1 = TP_sum / (TP_sum + FN_sum)
#recall2 = TN_sum / (TP_sum + FN_sum)
Accuracy = (TP_sum + TN_sum) / (TP_sum + TN_sum + FP_sum + FN_sum)
F1 = (2 * recall1 * presion) / (recall1 + presion)
# 预测结果前景iou
IOU1 = TP_sum / (TP_sum + FP_sum + FN_sum)
# 预测结果背景iou
IOU2 = TN_sum / (TN_sum + FP_sum + FN_sum)
# MIoU = (IoU正例p + IoU反例n) / 2 = [ TP / (TP + FP + FN) + TN / (TN + FN + FP) ] / 2
IOU = (IOU1 + IOU2) / 2
print("presion: ", presion)
print("recall: ", recall1)
print("Accuracy: ", Accuracy)
print("F1: ", F1)
print("mIou: ", IOU)
精度指标计算方式二
python
import os
import cv2
import numpy as np
from tqdm import tqdm
def read_binary_image(img_path):
"""
读取二值PNG图片,预处理为0/1矩阵
规则:背景=0,变化区域=255 → 统一转为 0(背景)/1(变化)
"""
# 读取为灰度图(自动兼容彩色图)
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise FileNotFoundError(f"无法读取图片: {img_path}")
# 二值化:大于0的像素设为1(兼容非标准255的二值图)
binary_img = np.where(img > 0, 1, 0).astype(np.uint8)
return binary_img
def calculate_confusion_matrix(label, pred):
"""
计算二分类混淆矩阵(变化检测:1=变化,0=背景)
返回: TP, FP, FN, TN
"""
# 确保标签和预测尺寸一致
if label.shape != pred.shape:
raise ValueError(f"尺寸不匹配: 标签{label.shape}, 预测{pred.shape}")
# 计算混淆矩阵
TP = np.sum((label == 1) & (pred == 1)) # 真正例:真实变化,预测变化
FP = np.sum((label == 0) & (pred == 1)) # 假正例:真实背景,预测变化
FN = np.sum((label == 1) & (pred == 0)) # 假反例:真实变化,预测背景
TN = np.sum((label == 0) & (pred == 0)) # 真反例:真实背景,预测背景
return TP, FP, FN, TN
def compute_metrics(TP, FP, FN, TN):
"""
根据混淆矩阵计算评估指标
"""
# 查准率 (Precision)
precision = TP / (TP + FP) if (TP + FP) != 0 else 0.0
# 查全率 (Recall)
recall = TP / (TP + FN) if (TP + FN) != 0 else 0.0
# F1分数
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) != 0 else 0.0
# IoU (变化类) + mIoU (二分类平均IoU)
iou_change = TP / (TP + FP + FN) if (TP + FP + FN) != 0 else 0.0
iou_bg = TN / (TN + FN + FP) if (TN + FN + FP) != 0 else 0.0
miou = (iou_change + iou_bg) / 2 # 平均交并比
return precision, recall, f1, miou, iou_change
def evaluate_change_detection(label_dir, pred_dir):
"""
主评估函数:批量读取文件夹,计算全局精度指标
"""
# 获取所有标签文件名
img_names = [f for f in os.listdir(label_dir) if f.endswith(('.png', '.PNG'))]
if len(img_names) == 0:
raise ValueError("标签文件夹中未找到PNG图片!")
# 初始化全局混淆矩阵
total_TP = 0
total_FP = 0
total_FN = 0
total_TN = 0
print(f"开始评估,共检测到 {len(img_names)} 张图片...")
# 遍历所有图片
for img_name in tqdm(img_names):
label_path = os.path.join(label_dir, img_name)
pred_path = os.path.join(pred_dir, img_name)
# 跳过预测文件缺失的情况
if not os.path.exists(pred_path):
print(f"警告:预测文件不存在,跳过 → {img_name}")
continue
try:
# 读取并预处理二值图
label = read_binary_image(label_path)
pred = read_binary_image(pred_path)
# 计算单张图片混淆矩阵
TP, FP, FN, TN = calculate_confusion_matrix(label, pred)
# 累加到全局统计
total_TP += TP
total_FP += FP
total_FN += FN
total_TN += TN
except Exception as e:
print(f"处理图片 {img_name} 失败: {str(e)}")
continue
# 计算最终全局指标
precision, recall, f1, miou, iou_change = compute_metrics(total_TP, total_FP, total_FN, total_TN)
# 打印结果
print("\n" + "=" * 50)
print("变化检测二值图评估结果(全局指标)")
print("=" * 50)
print(f"查准率 (Precision): {precision:.4f}")
print(f"查全率 (Recall) : {recall:.4f}")
print(f"F1 分数 : {f1:.4f}")
print(f"mIoU : {miou:.4f}")
print(f"变化类 IoU : {iou_change:.4f}")
print(f"总像素 TP: {total_TP}, FP: {total_FP}, FN: {total_FN}")
print("=" * 50)
return precision, recall, f1, miou
# ------------------- 【用户配置】修改这里的路径 -------------------
if __name__ == "__main__":
# 标签文件夹路径(真实变化检测二值图)
LABEL_DIR = r"./gray_label"
# 预测结果文件夹路径(模型输出的变化检测二值图)
PRED_DIR = r"./gray_result"
# 开始评估
evaluate_change_detection(LABEL_DIR, PRED_DIR)