#!/usr/bin/env python
#version    :       2023.12.31
#language   :       ch
from maix import camera
from maix import display
from maix import image
from maix import nn
from maix.nn import decoder
import os
import numpy as np

import os
ScreenOrientation = False
try:
    if os.path.exists("/etc/cameraSize.cfg"):
        cameraSize = True
    else:
        cameraSize = False
except:
    cameraSize = False
def getLcdRotation(cameraCapture):
    global cameraSize
    if cameraSize:
        return lcdRotationNew(cameraCapture)
    else:
        return lcdRotation(cameraCapture)

def lcdRotationNew(inputImg):
    global cameraSize,ScreenOrientation
    imageRotationBuffer = inputImg.crop(0, 0, 320, 240)
    if ScreenOrientation:
        imgRotationAim = image.new(size = (240, 320))
        rotationAngle = 90
        GETROTATION = imageRotationBuffer.rotate(+rotationAngle, adjust=1)
    else:
        imgRotationAim = image.new(size = (320, 240))
        GETROTATION = imageRotationBuffer

    GETROTATION = imgRotationAim.draw_image(GETROTATION,0,0,alpha=1)
    return GETROTATION

def lcdRotation(inputImg):
    global cameraSize,ScreenOrientation
    imageRotationBuffer = inputImg.crop(0, 0, 240, 320)
    if ScreenOrientation:
        imgRotationAim = image.new(size = (240, 320))
        rotationAngle = 180
    else:
        imgRotationAim = image.new(size = (320, 240))
        rotationAngle = 90
    GETROTATION = imageRotationBuffer.rotate(+rotationAngle, adjust=1)
    GETROTATION = imgRotationAim.draw_image(GETROTATION,0,0,alpha=1)
    return GETROTATION
   
def sigmoid(x):
    return 1/(1+np.exp(-x))

def grad(x):
    return x*(1-x)

class NeuralNetwork:
    """
    三层全连接前馈神经网络
    """

    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate, active_function=sigmoid, gradient=grad, lambda_=0.1):
        """

        :param inputnodes: 输入层结点数
        :param hiddennodes: 隐藏层节点数
        :param outputnodes: 输出层节点数
        :param learningrate: 学习率
        :param active_function: 激活函数
        :param gradient: 激活函数的导数
        :param lambda_: L2正则化系数
        """
        self.inputnodes = inputnodes
        self.hiddennodes = hiddennodes
        self.outputnodes = outputnodes
        self.learningrate = learningrate
        self.active_function = active_function
        self.gradient = gradient
        self.lambda_ = lambda_

        # 权值矩阵
        self.weights_i_h = np.random.rand(self.hiddennodes, self.inputnodes) - 0.5
        self.weights_h_o = np.random.rand(self.outputnodes, self.hiddennodes) - 0.5

    def train_sgd(self, x, y):
        """梯度下降训练"""
        train_x = np.array(x).reshape(-1,1)
        target = np.zeros((self.outputnodes,1)) + 0.01
        target[y,0] = 0.99

        hiddeninputs = np.dot(self.weights_i_h, train_x)
        hiddenoutputs = self.active_function(hiddeninputs)

        outputinputs = np.dot(self.weights_h_o, hiddenoutputs)
        final_outputs = self.active_function(outputinputs)

        error = target - final_outputs

        hidden_error = np.dot(self.weights_h_o.transpose(), error)

        self.weights_h_o += self.learningrate * error * np.dot(self.gradient(final_outputs), hiddenoutputs.transpose())

        self.weights_i_h += self.learningrate * hidden_error * np.dot(self.gradient(hiddenoutputs), train_x.transpose())

    def fit(self, train_x, targets):
        train_x = np.array(train_x)
        for i in range(train_x.shape[0]):
            self.train_sgd(train_x[i], targets[i])

    def query(self, inputs, debug=False):
        """单个值预测"""
        inputs = np.array(inputs).reshape(-1,1)
        hidden_input = np.dot(self.weights_i_h, inputs)
        hidden_output = self.active_function(hidden_input)

        output_input = np.dot(self.weights_h_o, hidden_output)

        final_output = self.active_function(output_input)

        if debug:
            print('predict: ', final_output)

        return np.argmax(final_output)

    def predict(self,inputs):
        """批量预测"""
        res = []
        for x in inputs:
            res.append(self.query(x))
        return res

    def __str__(self):
        return "NeuralNetwork: \ninput_nodes = {0}, hidden_nodes = {1}, \noutputnodes = {2}, learningrate = {3}".format(
            self.inputnodes, self.hiddennodes, self.outputnodes, self.learningrate
        )

image.load_freetype("/root/preset/fonts/CascadiaCodePL-Italic.ttf")

import pickle

if os.path.exists('/root/user/model/NN10.pkl'):
    with open('/root/user/model/NN10.pkl','rb') as f:
        b_data = pickle.load(f)
        net_model = pickle.loads(b_data)
else:
    # 最佳模型，载入最佳模型
    with open('/root/user/NN10.pkl','rb') as f:
        b_data = pickle.load(f)
        net_model = pickle.loads(b_data)
print(net_model)

if cameraSize==True:
    camera.camera.config(size=(320,240))
else:
    camera.camera.config(size=(240,320))
img_path="/root/user/image_1.png"
img_gray_path="/root/user/image_gray.png"
while True:
    img = getLcdRotation(camera.capture())                              #从摄像头中获取一张图像
    mk = img.crop(0, 0, 240, 240)                        #裁剪图像为320*240
    mk1=img.crop(0, 0, 240, 240).resize(224,224)        #继续裁剪图像为224*224
    canvas= image.new(size = (320, 240), color = (0,255,0), mode = 'RGB')    #创建背景图
    canvas.draw_image(mk1,58,8)        #贴224*224的图片
    mk2=mk1.resize(28,28)                                #裁剪图片为28*28
    canvas.draw_image(mk2,8,8)                            #贴28*28的图
    mk2.save(img_path)
    from PIL import Image
    origin=Image.open(img_path).convert('L')                #转为8位分辨率灰度图（0~255）
    origin.save(img_gray_path)
    origin_gray=image.open(img_gray_path)
    canvas.draw_image(origin_gray,8,48)
    img = np.array(origin).reshape(1, 784).astype('int')
    img = img / 255 * 0.99 + 0.01
    print(img.shape)

    tmp = net_model.query(img)
    print(tmp)
    if tmp:
        canvas.draw_string(12,80, str(tmp), scale = 5, color = (255,0,0) , thickness = 1)
    display.show(canvas)                                 #将图像显示出来
