import numpy as np
import lqmtest_x3_2_load_data

class ModelObj: # 网络对象
    def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
        self.ObjID = ObjID  # 图元号
        self.ObjType = ObjType  # 图元类别
        self.ObjLable = ObjLable  # 对象标签
        self.ParaString = ParaString  # 参数字符串
        self.ObjX = ObjX  # 对象位置x坐标
        self.ObjY = ObjY  # 对象位置y坐标
class Conv_Class(ModelObj):  # 卷积对象
    def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
        super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
        self.ConvProc = self.conv_proc  # 基本操作函数
        self.SetConvPara = self.setconv_para  # 参数设置函数
    # 定义卷积函数ConvProc()
    def conv_proc(self, image, ConvPara):
        # 获取输入数据的大小，这里假设是单通道的图片
        c, image_h, image_w = image.shape
        kernel_h = ConvPara["kernel_h"]
        kernel_w = ConvPara["kernel_w"]
        kernel = ConvPara["kernel"]
        out_h = (image_h - kernel_h) // ConvPara["stride"] + 1
        out_w = (image_w - kernel_w) // ConvPara["stride"] + 1
        output = np.zeros((c, out_h, out_w))  # 初始化输出数据为零矩阵
        for k in range(c):  # 遍历每个通道
            for i in range(out_h):  # 遍历每个输出位置
                for j in range(out_w):
                    stride = ConvPara["stride"]  # 获得步长
                    output[k, i, j] = np.sum(
                        image[k, i * stride:i * stride + 3, j *
                             stride:j * stride + 3] * kernel)#计算卷积
        return output  # 返回卷积计算后的数组（特征向量）
    def setconv_para(self):  # 定义设置卷积参数的函数SetConvPara()
        kernel_h = int(input("请输入卷积核的高度: "))  # 用户输入卷积核的高度 3
        kernel_w = int(input("请输入卷积核的宽度: "))  # 用户输入卷积核的宽度 3
        # 用户输入卷积核的值 
        kernel = [] 
        #           [[1.289202, -1.471377, -0.238452],
        #           [-0.562343, -0.019988, -0.441446],
        #           [1.627381, 1.390266, 0.812486]]
        print("请输入卷积核的值（一行一行输入，各值之间用空格分开）：")
        for i in range(kernel_h):
            row = [float(val) for val in input().split()]
            kernel.append(row)

        stride = int(input("请输入步长: "))  # 用户输入步长 1
        padding = int(input("请输入填充: "))  # 用户输入填充 0

        # 返回ConvPara参数，这里用一个字典来存储
        ConvPara = {"kernel": kernel, "kernel_h": kernel_h,
                    "kernel_w": kernel_w, "stride": stride,
                    "padding": padding}
        return ConvPara
if __name__ == '__main__':

    DataSet = lqmtest_x3_2_load_data.Data_Class("DataSet1", 1, "数据集1", [], 120, 330)
    # setload_data()函数，获取加载数据集的参数
    DataPara = DataSet.SetDataPara()
    train_images, test_images = DataSet.LoadData(DataPara)

    Conv = Conv_Class("Conv1", 2, "卷积1", [], 250, 330)
    ConvPara = Conv.SetConvPara()
    for i in range(len(train_images) // 32):
        images = train_images[i * 32:(i + 1) * 32]
        conv_images = []# 存储卷积处理后的图片的列表
        for image in images:# 获取训练集的图片数据
            dim = len(image.shape)# 获取矩阵的维度
            if dim == 2: # 如果是二维矩阵,则转化为三维矩阵
                image_h, image_w = image.shape
                image = np.reshape(image, (1,image_h,image_w))
                # 调用ConvProc()函数，根据ConvPara参数完成卷积计算
                output = Conv.ConvProc(image, ConvPara)
                conv_images.append(output)# 将卷积结果存储到列表
            elif dim == 3: # 若为三维矩阵，则保持不变直接卷积处理
                output = Conv.ConvProc(image, ConvPara)
                conv_images.append(output)
        # 将卷积处理后的图片列表转换为数组形式，方便后续处理
        conv_images = np.array(conv_images)
