系统级

控制中心

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 控制中心
{
    public partial class Control : Form
    {
        public Control()
        {
            InitializeComponent();
        }

        //定义回调:解决跨线程访问问题
        private delegate void SetTextValueCallBack(string strValue);
        private delegate void SetTextValueCallBack2(string strValue);
        private delegate void SetTextValueCallBack3(string strValue);
        //定义接收客户端发送消息的回调
        private delegate void ReceiveMsgCallBack(string strReceive);
        private delegate void ReceiveMsgCallBack2(string strReceive);
        //声明回调
        private SetTextValueCallBack setCallBack;
        private SetTextValueCallBack2 setCallBack2;
        private SetTextValueCallBack3 setCallBack3;
        //声明
        private ReceiveMsgCallBack receiveCallBack;
        private ReceiveMsgCallBack2 receiveCallBack2;

        //用于通信的Socket
        Socket socketProduct;
        //用于监听的SOCKET
        Socket socketWatch;

        //将远程连接的客户端的IP地址和Socket存入集合中
        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

        //创建监听连接的线程
        Thread AcceptSocketThread;
        //接收客户端发送消息的线程
        Thread threadReceive;
        //Thread threadReceive2;

        //变量设置
        public int sum_need = 0;
        public int sum_suit = 0;
        public int box_cap = 20;
        public int have_del = 0;
        public int have_box = 0;
        public bool isStart = false;


        
        //开始监听
        private void Start_Monitor_Click(object sender, EventArgs e)
        {
            //当点击开始监听的时候 在服务器端创建一个负责监听IP地址和端口号的Socket
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //获取ip地址
            IPAddress ip = IPAddress.Parse(this.txt_IP.Text.Trim());
            //创建端口号
            IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
            //绑定IP地址和端口号
            socketWatch.Bind(point);
            this.txt_Control.AppendText("监听成功" + " \r \n");
            //开始监听:设置最大可以同时连接多少个请求
            socketWatch.Listen(10);

            //实例化回调
            setCallBack = new SetTextValueCallBack(SetTextValue);
            setCallBack2 = new SetTextValueCallBack2(SetTextValue2);
            setCallBack3 = new SetTextValueCallBack3(SetTextValue3);
            receiveCallBack = new ReceiveMsgCallBack(ReceiveMsg);
            receiveCallBack2 = new ReceiveMsgCallBack2(ReceiveMsg2);

            //创建线程
            AcceptSocketThread = new Thread(new ParameterizedThreadStart(StartListen));
            AcceptSocketThread.IsBackground = true;
            AcceptSocketThread.Start(socketWatch);
        }

        /// 等待生产车间的连接,并且创建与之通信用的Socket
        private void StartListen(object obj)
        {
            Socket socketWatch = obj as Socket;
            while (true)
            {
                //等待客户端的连接,并且创建一个用于通信的Socket
                socketProduct = socketWatch.Accept();
                //获取远程主机的ip地址和端口号
                string strIp = socketProduct.RemoteEndPoint.ToString();
                //Console.WriteLine(strIp);
                dicSocket.Add(strIp, socketProduct);
                //Console.WriteLine(dicSocket.First().Key);
                //Console.WriteLine(dicSocket.Last().Key);
                //this.cmb_Socket.Invoke(setCmbCallBack, strIp);
                string strMsg = "远程主机:" + socketProduct.RemoteEndPoint + "连接成功";
                //this.txt_Control.AppendText(strMsg);
                //使用回调
                txt_Control.Invoke(setCallBack3, strMsg);

                //定义接收客户端消息的线程
                Thread threadReceive = new Thread(new ParameterizedThreadStart(Receive));
                threadReceive.IsBackground = true;
                threadReceive.Start(socketProduct);
                //Thread threadReceive2 = new Thread(new ParameterizedThreadStart(Receive2));
                //threadReceive2.IsBackground = true;
                //threadReceive2.Start(socketProduct);
            }
        }

        /// 控制中心不停的接收生产车间发送的消息
        private void Receive(object obj)
        {
            Socket socketSend = obj as Socket;
            while (true)
            {
                //客户端连接成功后,服务器接收客户端发送的消息
                byte[] buffer = new byte[2048];
                //实际接收到的有效字节数
                int count = socketSend.Receive(buffer);
                if (count == 0)//count 表示客户端关闭,要退出循环
                {
                    break;
                }
                else
                {
                    if (socketSend.RemoteEndPoint.ToString() == dicSocket.Last().Key)
                    {
                        string str = Encoding.Default.GetString(buffer, 0, count);
                        if(str== "装配完成,正在配送")
                        {
                            txt_Delivery.Invoke(receiveCallBack2, str);
                        }
                        else
                        {
                            string strReceiveMsg = "接收:" + socketSend.RemoteEndPoint + "发送的消息:" + "已完成装配" + str + "箱";
                            txt_Delivery.Invoke(receiveCallBack2, strReceiveMsg);
                        }
                    }
                    //txt_Produce.Invoke(receiveCallBack, strReceiveMsg);
                    else if (socketSend.RemoteEndPoint.ToString() == dicSocket.First().Key)
                    {
                        string str = Encoding.Default.GetString(buffer, 0, count);
                        string strReceiveMsg = "接收:" + socketSend.RemoteEndPoint + "发送的消息:" +"已生产防护服"+ str+"套";
                        txt_Produce.Invoke(receiveCallBack, strReceiveMsg);
                        sum_suit = int.Parse(str);
                        if (sum_suit - have_del >= 20 || sum_suit == sum_need)
                        {
                            //double temp = sum_suit - have_del / box_cap;
                            //string strMsg = (Math.Ceiling(temp)).ToString();
                            int inc = 1;
                            have_del = have_del + 20;
                            have_box++;
                            string strMsg = inc.ToString();
                            //Console.WriteLine(strMsg);
                            byte[] buffer_del = Encoding.Default.GetBytes(strMsg);
                            List<byte> list = new List<byte>();
                            //Console.WriteLine(list);
                            list.Add(0);
                            list.AddRange(buffer_del);
                            //将泛型集合转换为数组
                            byte[] newBuffer = list.ToArray();
                            //获得用户选择的IP地址
                            string ip = dicSocket.Last().Key.ToString();
                            //Console.WriteLine(newBuffer);
                            dicSocket[ip].Send(newBuffer);

                            //通知配送车间任务结束
                            if(sum_suit == sum_need)
                            {
                                int flag = 8;
                                string strFlag = flag.ToString();
                                byte[] buffer_flag = Encoding.Default.GetBytes(strFlag);
                                List<byte> list_flag = new List<byte>();
                                //Console.WriteLine(list);
                                list_flag.Add(0);
                                list_flag.AddRange(buffer_flag);
                                //将泛型集合转换为数组
                                byte[] newBuffer_flag = list_flag.ToArray();
                                //Console.WriteLine(newBuffer);
                                dicSocket[ip].Send(newBuffer_flag);
                            }
                        }
                    }
                    else
                    {
                        Console.WriteLine("生产结束");
                    }

                }


            }
        }

        ///// 控制中心不停的接收配送车间发送的消息
        //private void Receive2(object obj)
        //{
        //    Socket socketSend = obj as Socket;
        //    while (true)
        //    {
        //        //客户端连接成功后,服务器接收客户端发送的消息
        //        byte[] buffer = new byte[2048];
        //        //实际接收到的有效字节数
        //        int count = socketSend.Receive(buffer);
        //        if (count == 0)//count 表示客户端关闭,要退出循环
        //        {
        //            break;
        //        }
        //        else
        //        {
        //            //string strReceiveMsg1 = "这里是配送车间";
        //            //txt_Delivery.Invoke(receiveCallBack2, strReceiveMsg1);
        //            if (socketSend.RemoteEndPoint.ToString() == dicSocket.Last().Key)
        //            {
        //                string str = Encoding.Default.GetString(buffer, 0, count);
        //                string strReceiveMsg = "接收:" + socketSend.RemoteEndPoint + "发送的消息:" + str;
        //                txt_Delivery.Invoke(receiveCallBack2, strReceiveMsg);
        //                have_box = int.Parse(str);
        //                have_del = have_box * 20;
        //                threadReceive2.Interrupt();
        //            }
        //        }

        //    }
        //}

        /// 回调委托需要执行的方法
        private void SetTextValue(string strValue)
        {
            this.txt_Produce.AppendText(strValue + " \r \n");
        }

        private void SetTextValue2(string strValue)
        {
            this.txt_Delivery.AppendText(strValue + " \r \n");
        }

        private void SetTextValue3(string strValue)
        {
            this.txt_Control.AppendText(strValue + " \r \n");
        }

        private void ReceiveMsg(string strMsg)
        {
            this.txt_Produce.AppendText(strMsg + " \r \n");
        }

        private void ReceiveMsg2(string strMsg)
        {
            this.txt_Delivery.AppendText(strMsg + " \r \n");
        }

        //服务器给客户端发送消息
        private void btn_produce_Click(object sender, EventArgs e)
        {
            try
            {
                //string str_need = "123";
                //byte[] buffer_need = Encoding.Default.GetBytes(str_need);
                //dicSocket.First().Value.Send(buffer_need);

                sum_need = 0;
                sum_suit = 0;
                box_cap = 20;
                have_del = 0;
                have_box = 0;
                isStart = false;

                //把生产需求发给生产车间
                sum_need = int.Parse(this.txt_Need.Text.Trim());
                string strNeed = this.txt_Need.Text.Trim();
                byte[] buffer_need = Encoding.Default.GetBytes(strNeed);
                List<byte> list_need = new List<byte>();
                list_need.Add(0);
                list_need.AddRange(buffer_need);
                //将泛型集合转换为数组
                byte[] newBuffer_nedd = list_need.ToArray();
                //获得用户选择的IP地址
                string ip1 = dicSocket.First().Key.ToString();
                dicSocket[ip1].Send(newBuffer_nedd);


                    //double temp = sum_suit - have_del / box_cap;
                    //string strMsg = (Math.Ceiling(temp)).ToString();
                    //byte[] buffer = Encoding.Default.GetBytes(strMsg);
                    //List<byte> list = new List<byte>();
                    //list.Add(0);
                    //list.AddRange(buffer);
                    ////将泛型集合转换为数组
                    //byte[] newBuffer = list.ToArray();
                    ////获得用户选择的IP地址
                    //string ip = dicSocket.Last().Key.ToString();
                    //if (Math.Ceiling(temp) > 0)
                    //{
                    //    dicSocket[ip].Send(newBuffer);
                    //}

            }
            catch (Exception ex)
            {
                MessageBox.Show("给客户端发送消息出错:" + ex.Message);
            }
            //socketSend.Send(buffer);
        }

        //停止监听
        private void Stop_Monitor_Click(object sender, EventArgs e)
        {
            socketWatch.Close();
            socketProduct.Close();
            //终止线程
            AcceptSocketThread.Abort();
            threadReceive.Abort();
        }
    }
}


生产车间

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;

namespace 生产车间
{
    public partial class 生产车间 : Form
    {
        private int startY = 0;
        private int startY3 = 0;
        public 生产车间()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            timer1.Enabled = false;//timer控件初始化
            timer1.Interval = 50;
        }

        private static int sum_suit = 0;//已生产数量
        private static int sum_need = 0;//工作需求
        private static int isStart = 1;//是否开始
        //public static string IP ="192.168.1.143" ;
        //public static string IP_Port = "1111";

        //定义回调
        private delegate void SetTextCallBack(string strValue);
        //声明
        private SetTextCallBack setCallBack;

        //定义接收服务端发送消息的回调
        private delegate void ReceiveMsgCallBack(string strMsg);
        //声明
        private ReceiveMsgCallBack receiveCallBack;

        //创建连接的Socket
        Socket socketSend;
        //创建接收客户端发送消息的线程
        Thread threadReceive;




    private void Begin_Click(object sender, EventArgs e)
        {
            try
            {
                socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Parse(this.txt_IP.Text.Trim());
                socketSend.Connect(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
                //实例化回调
                setCallBack = new SetTextCallBack(SetValue);
                receiveCallBack = new ReceiveMsgCallBack(SetValueB);
                this.txt_Log.Invoke(setCallBack, "连接成功" + System.Environment.NewLine);

                //开启一个新的线程不停的接收服务器发送消息的线程
                threadReceive = new Thread(new ThreadStart(Receive));
                //设置为后台线程
                threadReceive.IsBackground = true;
                threadReceive.Start();
              
                //创建一个线程不停的生产
                    ThreadStart threadStart = new ThreadStart(Producing);
                    Thread thread = new Thread(threadStart);
                    thread.Start();
                //创建一个线程不停的发送
                ThreadStart threadStart1 = new ThreadStart(Sending);
                Thread thread1 = new Thread(threadStart1);               
                thread1.Start();
                timer1.Start();
                //创建一个线程不停更新窗口

               

            }
            catch (Exception ex)
            {
                MessageBox.Show("连接服务端出错:" + ex.ToString());
            }
        }

      

        public static void Producing()//这是不停生产的函数
        {
            while (true)
            {
                if (sum_suit < sum_need)
                {
                    
                    sum_suit++;
                    Thread.Sleep(1000);
                 
                    //休眠一秒
                    //  Console.WriteLine(sum_suit);
                }
                 if(sum_suit==sum_need&&sum_suit>0)
                {
                    sum_need = 0;
                    sum_suit = 0;
                }

            }

        }
        public void  Sending()//这是不停发送的函数
        {
            try
            {
                //               while (isStart == 1 && sum_need > sum_suit || isStart == 1 && sum_need == 0) 
                while (true)
                {
                    int x = sum_suit;
                    if (isStart == 1 && sum_need >= x)
                    {
                        if(sum_suit!=0)
                        this.txt_Log.AppendText("本次生产防护服" + sum_suit + "套 \r \n" + System.Environment.NewLine);
                        if (sum_suit == sum_need && sum_need != 0)//当sum_suit等于sum_need的时候x加1
                            x = sum_suit + 1;
                        if (sum_suit > 0)
                        {
                            string strMsg;
                            byte[] buffer;
                            int receive;
                            //   strMsg = sum_need.ToString();
                            strMsg = sum_suit.ToString();
                            buffer = new byte[2048];
                            buffer = Encoding.Default.GetBytes(strMsg);
                            receive = socketSend.Send(buffer);
                            Thread.Sleep(1000);
                          //  int y = sum_suit-1;
                          //  this.txt_Log.AppendText("本次生产防护服" + sum_suit + "套 \r \n"+ System.Environment.NewLine);
                            
                        }
                        else
                        {
                            Thread.Sleep(1000);
                        }

                        //           } while (isStart == 1 && sum_need+1 > sum_suit );
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发送消息出错:" + ex.Message);
            }


            //发送
        }
        /// 接收服务器发送的消息
        private void Receive()
    {
        try
        {
            while (true)
            {
                byte[] buffer = new byte[2048];
                //实际接收到的字节数
                int r = socketSend.Receive(buffer);
                if (r == 0)
                {
                    break;
                }
                else
                {
                    //判断发送的数据的类型
                    if (buffer[0] == 0)//表示发送的是文字消息
                    {
                        string str = Encoding.Default.GetString(buffer, 1, r - 1);
                             sum_need = int.Parse(str);
                            // this.txt_Log.Invoke(receiveCallBack, "接收远程服务器:" + socketSend.RemoteEndPoint + "发送的消息:" + str);
                            this.textBox.Invoke(receiveCallBack, str);
               
                            //break;

                        }
            
                }


            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("接收服务端发送的消息出错:" + ex.ToString());
        }
    }

    



    private void SetValue(string strValue)
        {
            this.txt_Log.AppendText(strValue + "\r \n");
        }
        private void SetValueB(string strValue)
        {
            this.textBox.AppendText(strValue + "\r \n");
        }



        private void Stop_Click(object sender, EventArgs e)
        {
            isStart = 0;
            //关闭socket
            socketSend.Close();
            //终止线程
            threadReceive.Abort();
            timer1.Stop();
        }

        //动画定时
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (sum_need > 0&&sum_need>sum_suit)
            {
                pictureBox2.Visible = true;
                pictureBox3.Visible = true;
                int i = pictureBox2.Location.X + 10;//图片坐标移动
                int j = pictureBox3.Location.X + 10;
                if (i > 700)
                {
                    i = 300;
                }
                if (j > 700)
                {
                    j = 300;
                }
                startY = pictureBox2.Location.Y;
                startY3 = pictureBox3.Location.Y;

                pictureBox2.Location = new Point(i, startY);
                pictureBox2.Refresh();//不断刷新
                pictureBox3.Location = new Point(j, startY3);
                pictureBox3.Refresh();//不断刷新
                timer1.Start();
            }
            else
            {
                pictureBox2.Visible = false;
                pictureBox3.Visible = false;
            }
        }
    }
}

运输中心

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;

namespace 客户端
{
    public partial class Form1 : Form
    {
        public static Form1 MainForm = null;
        public Form1()
        {
            InitializeComponent();
            MainForm = this;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        //定义回调
        private delegate void SetTextCallBack(string strValue);
        //声明
        private SetTextCallBack setCallBack;

        //定义接收服务端发送消息的回调
        private delegate void ReceiveMsgCallBack(string strMsg);
        //声明
        private ReceiveMsgCallBack receiveCallBack;

        //创建连接的Socket
        Socket socketSend;
        //创建接收客户端发送消息的线程
        Thread threadReceive;

        //已装箱数量(箱数)
        int have_box=0;
        //现在有的箱数
        int now_box;
        //连接
        private void Connect_Click(object sender, EventArgs e)
        {
            try
            {
                socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Parse(this.txt_IP.Text.Trim());
                socketSend.Connect(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
                //实例化回调
                setCallBack = new SetTextCallBack(SetValue);
                receiveCallBack = new ReceiveMsgCallBack(SetValue);
                this.txt_Log.Invoke(setCallBack, "连接成功");

                //开启一个新的线程不停的接收服务器发送消息的线程
                threadReceive = new Thread(new ThreadStart(Receive));
                //设置为后台线程
                threadReceive.IsBackground = true;
                threadReceive.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show("连接服务端出错:" + ex.ToString());
            }
        }

        /// 接口服务器发送的消息
        private void Receive()
        {
            try
            {
                while (true)
                {
                    byte[] buffer = new byte[2048];
                    //实际接收到的字节数
                    int r = socketSend.Receive(buffer);
                    if (r == 0)
                    {
                        break;
                    }
                    else
                    {
                        //判断发送的数据的类型
                        if (buffer[0] == 0)//表示发送的是文字消息
                        {
                            string str = Encoding.Default.GetString(buffer, 1, 2);
                            int now_box = int.Parse(str);
                            if (now_box==8)
                            {
                                string strMsg1 = "装配完成,正在配送";
                                byte[] buffer2 = new byte[2048];
                                buffer2 = Encoding.Default.GetBytes(strMsg1);
                                int receive = socketSend.Send(buffer2);
                                txt_Log.AppendText(System.Environment.NewLine+"装配完成,正在配送\n" );
                            }
                            else
                            {
                                //string temp = "接收远程服务器:" + socketSend.RemoteEndPoint + "发送的消息:" + "已生产" + str + "箱防护服";
                                this.txt_Log.Invoke(receiveCallBack, "接收远程服务器:" + socketSend.RemoteEndPoint + "发送的消息:"  + "正在生产" + str );
                                //   this.txt_Log.AppendText( "已生产" + str + "箱防护服" + System.Environment.NewLine);
                                int j = now_box;
                                for (int i = 0; i < j; i++)
                                {
                                    now_box--;
                                    have_box++;
                                    this.txt_Log.Invoke(receiveCallBack,  "箱防护服" + System.Environment.NewLine+"装配防护服中......");
                                    pictureMove();

                                    
                                   
                                    this.txt_Log.Invoke(receiveCallBack, "已装配" + have_box + "箱" + "," + "剩余" + now_box + "箱");
                                }

                                //发送已装配数量给服务端
                                string strMsg = have_box.ToString();
                                byte[] buffer1 = new byte[2048];
                                buffer1 = Encoding.Default.GetBytes(strMsg);
                                int receive = socketSend.Send(buffer1);
                            }
                            
                        }
                        //表示发送的是文件
                        if (buffer[0] == 1)
                        {
                            SaveFileDialog sfd = new SaveFileDialog();
                            sfd.InitialDirectory = @"";
                            sfd.Title = "请选择要保存的文件";
                            sfd.Filter = "所有文件|*.*";
                            sfd.ShowDialog(this);

                            string strPath = sfd.FileName;
                            using (FileStream fsWrite = new FileStream(strPath, FileMode.OpenOrCreate, FileAccess.Write))
                            {
                                fsWrite.Write(buffer, 1, r - 1);
                            }

                            MessageBox.Show("保存文件成功");
                        }
                    }


                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("接收服务端发送的消息出错:" + ex.ToString());
            }
        }

        private void SetValue(string strValue)
        {
            this.txt_Log.AppendText(strValue + "\r \n");
        }

        //客户端给服务器发送消息
        //private void Send_Click(object sender, EventArgs e)
        //{
        //    try
        //    {
        //        string strMsg = this.txt_Msg.Text.Trim();
        //        byte[] buffer = new byte[2048];
        //        buffer = Encoding.Default.GetBytes(strMsg);
        //        int receive = socketSend.Send(buffer);
        //    }
        //    catch (Exception ex)
        //    {
        //        MessageBox.Show("发送消息出错:" + ex.Message);
        //    }
        //}

        //断开连接
        private void CloseConnect_Click(object sender, EventArgs e)
        {
            //关闭socket
            socketSend.Close();
            //终止线程
            threadReceive.Abort();
        }

        //public partial class Form1 : Form
        //{
        //    public static Form1 mainFrm;
        //    public Form1()
        //    {
        //        mainFrm = this;
        //    }
        //}
       
        public static void pictureMove()
        {
            // Form1.MainForm.pictureBox1.Visible = true;
            //Form1.MainForm.pictureBox2.Show();
            for (int i = 0; i < 6; i++)
            {
                DateTime orinowTime = DateTime.Now;//记录延时开始的系统当前时间
                while (orinowTime.AddSeconds(0.6).CompareTo(DateTime.Now) >= 0)
                {
                }
                Form1.MainForm.pictureBox1.Left += 80;

            }
            Form1.MainForm.pictureBox1.Visible = false;
            Form1.MainForm.pictureBox1.Left =81;
            Form1.MainForm.pictureBox1.Visible = true;


            Form1.MainForm.pictureBox2.Show();
            DateTime orinowTim = DateTime.Now;//记录延时开始的系统当前时间
            while (orinowTim.AddSeconds(0.5).CompareTo(DateTime.Now) >= 0)
            {
                //Form1.MainForm.pictureBox2.Visible = true;
            }
            Form1.MainForm.pictureBox2.Hide();
            //Form1.MainForm.pictureBox2.Visible = true;
            //DateTime orinowTim = DateTime.Now;//记录延时开始的系统当前时间
            //while (orinowTim.AddSeconds(1).CompareTo(DateTime.Now) >= 0)
            //{
            //    //Form1.MainForm.pictureBox2.Visible = true;
            //}
            //Form1.MainForm.pictureBox2.Visible = false;

        }

       
        private void button1_Click_1(object sender, EventArgs e)
        {
            pictureMove();
        }
    }
}

测试

<pre>



#include <iostream>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <map>

#include "opencv2/imgproc/imgproc.hpp"

using namespace std;
using namespace cv;
#include<vector>
#include<string>
#include <opencv2/features2d.hpp>
#include <opencv2/photo.hpp>
#include<set>

//高斯滤波





int getThreshold(Mat grayImg)
{
	//1.求灰度直方图
	vector<int>histo(256);
	for (int i = 0; i < grayImg.rows; i++)
	{
		for (int j = 0; j < grayImg.cols; j++)
		{
			histo[grayImg.at<uchar>(i, j)]++;
		}
	}
	//2.根据上面的直方图 用迭代法求阈值
	int count0, count1;//count0,count1分别是大于t0和小于t0的像素点的个数

	int t0 = 150, t = 0; //t0是初始的阈值,t是每一次经过迭代运算后的阈值 当t=t0时认为找到

	int z0, z1;      //z0,在z1分别是大于t0和小于t0的像素值的总和
	while (1)
	{
		count0 = count1 = z0 = z1 = 1;
		for (int i = 0; i < histo.size(); i++)
		{
			if (i <= t0)
			{
				count0 += histo[i];
				z0 += i * histo[i];
			}
			else
			{
				count1 += histo[i];
				z1 += i * histo[i];
			}
		}

		t = (z0 / count0 + z1 / count1) / 2;
		if (t0 == t)
			break;
		else t0 = t;
	}
	return  t0 - 11;
}

Mat Hough(Mat srcImage)
{
	Mat grad_y;
	//调整第六个参数  有不同的效果1,3,5,7 第3个参数也可以换具体参照254页
	Sobel(srcImage, grad_y, -1, 0, 1, 5);
	vector<Vec2f>lines;
	HoughLines(grad_y, lines, 1, CV_PI / 180, 210);
	float sum = 0;
	for (int i = 0; i < lines.size(); i++)
	{
		sum += lines[i][1];
	}
	float alpha = 0;
	if (lines.size() == 0)
	{
		alpha = CV_PI / 2;
	}


	else
	{
		alpha = sum / lines.size();
	}
	alpha = alpha * 180 / CV_PI - 90;
	Mat dstImage;
	double width = srcImage.cols, height = srcImage.rows;
	//Point2f center(srcImage.cols / 2, srcImage.rows / 2);
	Mat M = getRotationMatrix2D(Point(width / 2, height / 2), alpha, 1);
	warpAffine(srcImage, dstImage, M, srcImage.size());
	//imshow("旋转", dstImage);
	return dstImage;
}


//侵蚀操作
//Mat qinshi(Mat& img)
//{
//
//	//	namedWindow("原始图", WINDOW_NORMAL);
//	//	imshow("原始图", img); 
//	Mat out;
//	//获取自定义核
//	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); //第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
//	//腐蚀操作
//	dilate(img, out, element);
//	//同一图片大小
//	double width = 800;
//	double height = width * img.rows / img.cols;
//	resize(out, out, Size(width, height));
//
//	//imshow("腐蚀操作", out);
//	return out;
//}


Mat splitbian(Mat& src_img)
{
	Mat mattemp = src_img.clone();//深度拷贝
	int height = src_img.rows, width = src_img.cols;//赋值
	vector<int>hang(src_img.rows);
	vector<int>lie(src_img.cols);
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src_img.at<uchar>(i, j) != 0)
			{
				hang[i]++;
				lie[j]++;
			}
		}
	}
	/*cout << "每列的和:" << endl;
	for (int i = 0; i < width; i++)
		cout << lie[i] << "  " << i << endl;

	cout << "每行的和:" << endl;
	for (int i = 0; i < height; i++)
		cout << hang[i] << "   ";*/
	int shangqie = 0;  //表示左上的y
	for (int i = 0; i < height; i++)
	{
		if (hang[i] > 400)
			shangqie = i;
		if (hang[i] < 400)
		{
			//shangqie = i;
			break;
		}
	}
	int xiaqie = (height / 20) * 19;//表示右下的y
	for (int i = height - 1; i > (height / 20) * 19; i--)
	{
		if (hang[i] > 400)
			xiaqie = i;
		if (hang[i] < 400)
		{
			//	xiaqie = i;
			break;
		}

	}
	int zuoqie = (width / 20);
	for (int i = 0; i < width; i++)
	{
		if (lie[i] > 400)
			zuoqie = i;
		if (lie[i] < 400)
		{
			//zuoqie = i;
			break;
		}

	}
	int youqie = (width / 20) * 19;
	for (int i = width - 1; i > (width / 20) * 19; i--)
	{
		if (lie[i] > 300)
			youqie = i;
		if (lie[i] < 200)
			break;
	}
	if (zuoqie < (width / 10))
	{
		zuoqie = zuoqie;
	}
	else
		zuoqie = (width / 10);
	const Rect img1 = Rect(zuoqie, 0, youqie - zuoqie - 5, height);
	Mat temp1;
	temp1 = src_img(img1);
	//	imshow("裁剪图", temp1);

	waitKey();
	return temp1;
}

int th(Mat src_img)
{
	Mat mattemp = src_img.clone();//深度拷贝
	int height = src_img.rows, width = src_img.cols;//赋值
	int sum = 0;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src_img.at<uchar>(i, j) != 0)
			{
				sum++;
			}
		}
	}

	return sum;
}


//水平投影
Mat splitrow(Mat mat)
{

	Mat mattemp = mat.clone();//深度拷贝
	//	imshow("原图", mattemp);
		//waitKey();
	int height = mattemp.rows, width = mattemp.cols;
	int temp = 0;//存储255灰度级的个数?
	int* heightnum = new int[height];//行号//保存每一行255数目的数组
	int y1 = height;
	int y2 = 0;
	//开始遍历二维数组
	for (int i = 0; i < height; i++)
	{
		temp = 0;
		for (int j = 0; j < width; j++)
		{
			if (mattemp.at<uchar>(i, j) != 0)
			{
				temp++;//统计白色

			}
		}
		//一行完了
		heightnum[i] = temp;
		//cout << heightnum[i] << "   " << i << endl;

	}




	for (int i = 0; i < height - 1; i++)
	{


		if (heightnum[i] < 10 && heightnum[i + 10]>10)
		{
			y1 = i;

			cout << "y1是:" << y1 << endl;
			break;
		}

	}
	for (int i = y1 + 10; i < height - 1; i++)
	{


		if (heightnum[i] < 10)
		{
			y2 = i;
			cout << "y2是:" << y2 << endl;
			break;

		}
	}
	cout << "执行完毕" << endl;
	Mat temp1;
	if (y1 > height / 2 || y2 > height / 3 * 2)
	{
		temp1 = splitbian(mat);
		temp1 = splitrow(temp1);

	}
	else
	{
		if (y2 - y1 <= 20)
			y2 = y1 + 60;


		//开始切割图片

		//设横轴是x轴,竖轴是y轴
		//这个先输入x ,后输入y
		Rect img1 = Rect(0, y1, width, y2 - y1 + 5);
		temp1 = mat(img1);
		//imshow("裁剪图", temp1);
		//waitKey();
	}
	delete[] heightnum;
	return temp1;


}






//垂直投影截取列
//竖直投影分割列
void splitCol(Mat& mat, int* position1, int* position2, int* stringwidth, int& idx)
{
	cout << "开始垂直投影" << endl;

	Mat mattemp = mat.clone();//深度拷贝
	//imshow("原图", mattemp);
	int height = mattemp.rows, width = mattemp.cols;//赋值
	int* proj = new int[width];



	for (int col = 0; col < width; col++)
	{
		int temp = 0;
		for (int row = 0; row < height; row++)
		{
			if (mattemp.at<uchar>(row, col) != 0)
			{
				temp++;
			}
		}
		proj[col] = temp;  //统计白的个数

	}
	//    //黑底白字 遇到黑是字
		  //for (int i = 0; i < height; i++)
		  //	cout << proj[i] << endl;
		  //确认字符位置

	int count = 1;
	int pix;//字符的分割位置
	//int position1[100000];//第一次遇到白色的位置
	//int position2[100000];//第二次遇到白色的位置
	for (int i = 0; i < width; i++)
	{
		pix = proj[i];
		if (pix >= 2 && (count % 2 != 0))  //遇到黑色了要开始剪了
		{
			if (i - 1 > 0)
				position1[idx] = i - 1;
			else
				position1[idx] = i;
			count++;
			continue;
		}
		else if (pix < 2 && (count % 2 == 0))//遇到 白色剪的停止位置
		{
			if (i + 1 < width)
				position2[idx] = i + 1;
			else
				position2[idx] = i;
			count++;
			idx++;
		}

		//if (i > (width - 2) && (count % 2 != 0))  //前边有一半了,但是这后一半没找到
		//{
		//	
		//	position2[idx] = i;
		//	count++;
		//	idx++;
		//}

	}


	//记录所有字符的宽度
	for (int i = 0; i < idx; i++)
	{
		stringwidth[i] = position2[i] - position1[i];
		//	cout << "宽为:"<< stringwidth[i] << endl;
	}




	//Mat number_img = Mat(Scalar(0));
	//for (int i = 0; i < idx; i++) 
	//{
	//	Rect choose_rect(position1[i], 0, swidth[i], height);
	//	number_img = mat(choose_rect);
	//	imshow("number" + to_string(i), number_img);
	//
	//	// imwrite("number" + to_string(i) + ".jpg", number_img);
	//}

}



//找最小矩阵
void findminjuzhen(Mat src, pair<int, int>& num1, pair<int, int>& num2)
{


	int height = src.rows, width = src.cols;//赋值
	vector<int>hang(src.rows);
	vector<int>lie(src.cols);
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src.at<uchar>(i, j) != 0)
			{
				hang[i]++;
				lie[j]++;
			}
		}
	}
	for (int i = 0; i < height; i++)
		if (hang[i] != 0)
			num1.second = i;    //最下界
	for (int i = 0; i < width; i++)
		if (lie[i] != 0)
			num2.second = i;
	for (int i = height - 1; i >= 0; i--)
		if (hang[i] != 0)
			num1.first = i; //最上界
	for (int i = width - 1; i >= 0; i--)
		if (lie[i] != 0)
			num2.first = i;




	cout << "(" << num1.first << " " << num1.second << ")";  //上下边界
	cout << " ";
	cout << "(" << num2.first << " " << num2.second << ")";//左右边界

}

//字符匹配
//首先是两张图作差
double imgcha(Mat inimg1, Mat mubanimg)
{
	//记录两张图不同的像素点的个数
	double difnum = 0;
	//cvtColor(mubanimg, mubanimg, COLOR_BGR2GRAY);
	//threshold(mubanimg, mubanimg, getThreshold( mubanimg), 255, THRESH_OTSU);  //模板二值化
	//同样大小的处理
	resize(inimg1, inimg1, Size(30, 55));
	resize(mubanimg, mubanimg, Size(30, 55));

	Mat temp0;
	absdiff(inimg1, mubanimg, temp0);
	for (int i = 0; i < temp0.rows; i++)
	{
		for (int j = 0; j < temp0.cols; j++)
		{
			difnum += temp0.at<uchar>(i, j);
		}
	}

	return difnum;  //返回不一样的值
}
typedef pair<double, int>PDL;
int pathnum = 0;


void splitSample(char ch, int k, Mat inputImg)
{
	string st = to_string(k) + ".jpg";
	//cout << st << endl;
	imwrite("F:\\erjixiangmu\\erjixiangmu\\muban2\\" + to_string(ch - 48) + "." + st, inputImg);

}
char recognition(Mat inputImg, int k)
{
	string sampleimgpathall = "muban";
	vector<String> sampleimgpath;
	glob(sampleimgpathall, sampleimgpath, false);//读取模板所有的路径,存到FN里面
	int sampleimgnum = sampleimgpath.size();
	vector<pair< double, int> >nums(sampleimgnum + 1);//i表示图片在路径vector里的下标 并存储该图片和模板里的图片的差
	for (int i = 0; i < sampleimgnum; i++) {

		Mat numImg = imread(sampleimgpath[i], 0);
		//大小同一
		resize(numImg, numImg, Size(40, 60));
		resize(inputImg, inputImg, Size(40, 60));
		nums[i].first = imgcha(inputImg, numImg);//不同像素值的差
		nums[i].second = i;//在迭代器中的下标
	}
	// imshow("图片", inputImg);
	waitKey();
	//排序 越小说明匹配度越高
	sort(&nums[0], &nums[sampleimgnum]);
	int index = nums[0].second; //读取模板里的该图片
	//截取模板的函数
	splitSample(sampleimgpath[index][sampleimgpathall.size() + 1], k, inputImg);
	return sampleimgpath[index][sampleimgpathall.size() + 1];

}


//图像锐化
Mat ToSharoen(Mat inputImage)
{
	Mat outputImage(inputImage.size(), inputImage.type());
	int cnel = inputImage.channels();
	int rows = inputImage.rows;
	int cols = (inputImage.cols - 1) * cnel;

	for (int row = 1; row < rows - 1; row++)
	{
		const uchar* previous = inputImage.ptr<uchar>(row - 1);
		const uchar* current = inputImage.ptr<uchar>(row);
		const uchar* next = inputImage.ptr<uchar>(row + 1);
		uchar* output = outputImage.ptr(row);
		for (int col = cnel; col < cols; col++)
		{
			output[col] = saturate_cast<uchar>(5 * current[col] - (previous[col] + current[col + 1] + current[col - 1] + next[col]));
		}
	}
	//namedWindow("锐化图", WINDOW_AUTOSIZE);
	//imshow("锐化图", outputImage);
	return outputImage;
}

// 图像锐化





int main()
{
	int imgsum = 0, rightimg = 0;
	int stringnum = 0, rightstringnum = 0;
	int errornum = 0;
	//读取ISBN图片
	string testimgpathall = "ISBN";
	vector<string>testimgpath;//存储单个图片的路径

	glob(testimgpathall, testimgpath, false);//读取函数
	int testimgsums = testimgpath.size();
	vector<string>errorpath(testimgsums);
	vector<int>yuzhi(testimgsums);
	//开始对每一个ISBN进行操作
	for (int testindex = 0; testindex < testimgsums; testindex++)
	{
		cout << "开始处理第" << testindex << "张照片" << endl;
		Mat src = imread(testimgpath[testindex]);

		//同一图片大小
		double width = 600;
		double height = width * src.rows / src.cols;
		resize(src, src, Size(width, height));
		//imshow("原图", src);

		Mat gary_src;
		cvtColor(src, gary_src, COLOR_BGR2GRAY);
		//imshow("灰度图", gary_src);

		Mat gary_sharoen = ToSharoen(gary_src);
		//imshow("锐化后的灰度图", gary_sharoen);
		// 
			//高斯去噪处理
		Mat gas;
		GaussianBlur(gary_sharoen, gas, Size(7, 7), 1, 1);
		//	imshow("高斯去噪后的灰度图", gas);
		waitKey();




		//二值化
		Mat binImg;
		int thethreshold = getThreshold(gas);
		cout << "阈值为:" << thethreshold << endl;
		//	THRESH_BINARY (白底黑字)、THRESH_BINARY_INV(黑底白字)
			//THRESH_TRUNC(很暗很暗)THRESH_OTSU
		if (thethreshold < 123)
			thethreshold = thethreshold;
		else
			thethreshold += 31;

		threshold(gas, binImg, thethreshold, 255, THRESH_BINARY_INV);

		//判断是白底还是黑底图
		int thethreshold2 = th(binImg);
		cout << "白点数:" << thethreshold2;
		if (thethreshold2 > 190000)
		{
			cout << "白底图";
			threshold(gas, binImg, thethreshold, 255, THRESH_BINARY);
		}
		else
			threshold(gas, binImg, thethreshold, 255, THRESH_BINARY_INV);


		//	imshow("二值化图", binImg);
		waitKey();
		//旋转
		Mat temp1 = Hough(binImg);



		//	imshow("二值化图片进行霍夫旋转", temp1);
		waitKey();




		//水平裁剪

		Mat shui_img;
		shui_img = splitrow(temp1);
		//	imshow("水平剪完的二值图", shui_img);
		waitKey();
		//侵蚀一下
			//shui_img = qinshi(shui_img);
			//imshow("水平寝室", shui_img);
		waitKey();


		//做列的分割
		int position1[100000];//第一次遇到白色的位置
		int position2[100000];//第二次遇到白色的位置
		int  swidth[1000];//记录字符宽
		int posidx = 0;

		//垂直裁剪
		splitCol(shui_img, position1, position2, swidth, posidx);
		//开始对每个数字进行处理

		string ans = "";
		Mat number_img = Mat(Scalar(0));
		for (int i = 4; i < posidx; i++)
		{
			//Mat subImg = Mat(shuiimg, Range(0, shuiimg.rows), Range(position1[i], position2[i]));
			//做列分割
			Rect choose_rect(position1[i], 0, swidth[i], shui_img.rows);
			number_img = shui_img(choose_rect);
			//	imshow("垂直投影的分割图" + to_string(i), number_img);
			waitKey();
			//找该数字的最小矩阵
			pair<int, int> num1;
			pair<int, int> num2;
			findminjuzhen(number_img, num1, num2);
			//imshow("最小矩阵", number_img);
			//waitKey();
			int numimgheight = num1.second - num1.first;
			int numimgwidth = num2.second - num2.first;
			if (numimgheight > numimgwidth / 2 && numimgwidth > 3 && numimgheight > 5)
			{
				Mat minImg = Mat(number_img, Range(num1.first, num1.second + 1), Range(num2.first, num2.second + 1));
				// imshow("最小矩形", minImg);
				//waitKey();
				//是数字或者字母
				char ch = recognition(minImg, testindex);
				//char ch = pipei(minImg);
				if (ch >= '0' && ch <= '9')
				{
					ans += ch;
					cout << ch << " ";
				}
			}



		}
		cout << endl;

		//现在开始对比
		cout << "现在的路径是:" << testimgpath[testindex] << endl;
		string rightans = "";
		for (int i = 0; i < testimgpath[testindex].length(); i++)
		{
			char temp = testimgpath[testindex][i];
			if (temp >= '0' && temp <= '9')
			{
				rightans += temp;
			}
		}

		cout << "正确的数据是:" << rightans << endl;
		cout << "读出来的答案是:" << ans << endl;
		stringnum += rightans.length();//总的字符数
		int ansidx = min(ans.length(), rightans.length());
		bool right = true;
		for (int i = 0; i < ansidx; i++)
		{
			if (ans[i] != rightans[i])
				right = false;
			else
				rightstringnum++;//答对的字符数				
		}
		if (ans.length() == rightans.length() && right)//识别正确
		{
			rightimg++;
			cout << "YES" << endl;
		}
		else
		{
			cout << "NO" << endl;
			cout << "-------------------------------------" << endl;

			errorpath[errornum] = testimgpath[testindex];
			errornum++;
		}

	}
	printf("正确个数:%4.d 正确率:%f\n", rightimg, rightimg * 1.0 / testimgsums);
	printf("准确个数:%4.d 准确率:%f\n", rightstringnum, rightstringnum * 1.0 / stringnum);



	for (int i = 0; i < errornum; i++)
		cout << "错误的路径是:" << errorpath[i] << endl;

	waitKey(0);

}

<pre>

代码参考

#include <iostream>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <map>

#include "opencv2/imgproc/imgproc.hpp"

using namespace std;
using namespace cv;
#include<vector>
#include<string>
#include <opencv2/features2d.hpp>
#include <opencv2/photo.hpp>
#include<set>

//高斯滤波





int getThreshold(Mat grayImg)
{
	//1.求灰度直方图
	vector<int>histo(256);
	for (int i = 0; i < grayImg.rows; i++)
	{
		for (int j = 0; j < grayImg.cols; j++)
		{
			histo[grayImg.at<uchar>(i, j)]++;
		}
	}
	//2.根据上面的直方图 用迭代法求阈值
	int count0, count1;//count0,count1分别是大于t0和小于t0的像素点的个数

	int t0 = 150, t = 0; //t0是初始的阈值,t是每一次经过迭代运算后的阈值 当t=t0时认为找到

	int z0, z1;      //z0,在z1分别是大于t0和小于t0的像素值的总和
	while (1)
	{
		count0 = count1 = z0 = z1 = 1;
		for (int i = 0; i < histo.size(); i++)
		{
			if (i <= t0)
			{
				count0 += histo[i];
				z0 += i * histo[i];
			}
			else
			{
				count1 += histo[i];
				z1 += i * histo[i];
			}
		}

		t = (z0 / count0 + z1 / count1) / 2;
		if (t0 == t)
			break;
		else t0 = t;
	}
	return  t0 - 11;
}

Mat Hough(Mat srcImage)
{
	Mat grad_y;
	//调整第六个参数  有不同的效果1,3,5,7 第3个参数也可以换具体参照254页
	Sobel(srcImage, grad_y, -1, 0, 1, 5);
	vector<Vec2f>lines;
	HoughLines(grad_y, lines, 1, CV_PI / 180, 210);
	float sum = 0;
	for (int i = 0; i < lines.size(); i++)
	{
		sum += lines[i][1];
	}
	float alpha = 0;
	if (lines.size() == 0)
	{
		alpha = CV_PI / 2;
	}


	else
	{
		alpha = sum / lines.size();
	}
	alpha = alpha * 180 / CV_PI - 90;
	Mat dstImage;
	double width = srcImage.cols, height = srcImage.rows;
	//Point2f center(srcImage.cols / 2, srcImage.rows / 2);
	Mat M = getRotationMatrix2D(Point(width / 2, height / 2), alpha, 1);
	warpAffine(srcImage, dstImage, M, srcImage.size());
	//imshow("旋转", dstImage);
	return dstImage;
}


//侵蚀操作
//Mat qinshi(Mat& img)
//{
//
//	//	namedWindow("原始图", WINDOW_NORMAL);
//	//	imshow("原始图", img); 
//	Mat out;
//	//获取自定义核
//	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); //第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
//	//腐蚀操作
//	dilate(img, out, element);
//	//同一图片大小
//	double width = 800;
//	double height = width * img.rows / img.cols;
//	resize(out, out, Size(width, height));
//
//	//imshow("腐蚀操作", out);
//	return out;
//}


Mat splitbian(Mat& src_img)
{
	Mat mattemp = src_img.clone();//深度拷贝
	int height = src_img.rows, width = src_img.cols;//赋值
	vector<int>hang(src_img.rows);
	vector<int>lie(src_img.cols);
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src_img.at<uchar>(i, j) != 0)
			{
				hang[i]++;
				lie[j]++;
			}
		}
	}
	/*cout << "每列的和:" << endl;
	for (int i = 0; i < width; i++)
		cout << lie[i] << "  " << i << endl;

	cout << "每行的和:" << endl;
	for (int i = 0; i < height; i++)
		cout << hang[i] << "   ";*/
	int shangqie = 0;  //表示左上的y
	for (int i = 0; i < height; i++)
	{
		if (hang[i] > 400)
			shangqie = i;
		if (hang[i] < 400)
		{
			//shangqie = i;
			break;
		}
	}
	int xiaqie = (height / 20) * 19;//表示右下的y
	for (int i = height - 1; i > (height / 20) * 19; i--)
	{
		if (hang[i] > 400)
			xiaqie = i;
		if (hang[i] < 400)
		{
			//	xiaqie = i;
			break;
		}

	}
	int zuoqie = (width / 20);
	for (int i = 0; i < width; i++)
	{
		if (lie[i] > 400)
			zuoqie = i;
		if (lie[i] < 400)
		{
			//zuoqie = i;
			break;
		}

	}
	int youqie = (width / 20) * 19;
	for (int i = width - 1; i > (width / 20) * 19; i--)
	{
		if (lie[i] > 300)
			youqie = i;
		if (lie[i] < 200)
			break;
	}
	if (zuoqie < (width / 10))
	{
		zuoqie = zuoqie;
	}
	else
		zuoqie = (width / 10);
	const Rect img1 = Rect(zuoqie, 0, youqie - zuoqie - 5, height);
	Mat temp1;
	temp1 = src_img(img1);
	//	imshow("裁剪图", temp1);

	waitKey();
	return temp1;
}

int th(Mat src_img)
{
	Mat mattemp = src_img.clone();//深度拷贝
	int height = src_img.rows, width = src_img.cols;//赋值
	int sum = 0;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src_img.at<uchar>(i, j) != 0)
			{
				sum++;
			}
		}
	}

	return sum;
}


//水平投影
Mat splitrow(Mat mat)
{

	Mat mattemp = mat.clone();//深度拷贝
	//	imshow("原图", mattemp);
		//waitKey();
	int height = mattemp.rows, width = mattemp.cols;
	int temp = 0;//存储255灰度级的个数?
	int* heightnum = new int[height];//行号//保存每一行255数目的数组
	int y1 = height;
	int y2 = 0;
	//开始遍历二维数组
	for (int i = 0; i < height; i++)
	{
		temp = 0;
		for (int j = 0; j < width; j++)
		{
			if (mattemp.at<uchar>(i, j) != 0)
			{
				temp++;//统计白色

			}
		}
		//一行完了
		heightnum[i] = temp;
		//cout << heightnum[i] << "   " << i << endl;

	}




	for (int i = 0; i < height - 1; i++)
	{


		if (heightnum[i] < 10 && heightnum[i + 10]>10)
		{
			y1 = i;

			cout << "y1是:" << y1 << endl;
			break;
		}

	}
	for (int i = y1 + 10; i < height - 1; i++)
	{


		if (heightnum[i] < 10)
		{
			y2 = i;
			cout << "y2是:" << y2 << endl;
			break;

		}
	}
	cout << "执行完毕" << endl;
	Mat temp1;
	if (y1 > height / 2 || y2 > height / 3 * 2)
	{
		temp1 = splitbian(mat);
		temp1 = splitrow(temp1);

	}
	else
	{
		if (y2 - y1 <= 20)
			y2 = y1 + 60;


		//开始切割图片

		//设横轴是x轴,竖轴是y轴
		//这个先输入x ,后输入y
		Rect img1 = Rect(0, y1, width, y2 - y1 + 5);
		temp1 = mat(img1);
		//imshow("裁剪图", temp1);
		//waitKey();
	}
	delete[] heightnum;
	return temp1;


}






//垂直投影截取列
//竖直投影分割列
void splitCol(Mat& mat, int* position1, int* position2, int* stringwidth, int& idx)
{
	cout << "开始垂直投影" << endl;

	Mat mattemp = mat.clone();//深度拷贝
	//imshow("原图", mattemp);
	int height = mattemp.rows, width = mattemp.cols;//赋值
	int* proj = new int[width];



	for (int col = 0; col < width; col++)
	{
		int temp = 0;
		for (int row = 0; row < height; row++)
		{
			if (mattemp.at<uchar>(row, col) != 0)
			{
				temp++;
			}
		}
		proj[col] = temp;  //统计白的个数

	}
	//    //黑底白字 遇到黑是字
		  //for (int i = 0; i < height; i++)
		  //	cout << proj[i] << endl;
		  //确认字符位置

	int count = 1;
	int pix;//字符的分割位置
	//int position1[100000];//第一次遇到白色的位置
	//int position2[100000];//第二次遇到白色的位置
	for (int i = 0; i < width; i++)
	{
		pix = proj[i];
		if (pix >= 2 && (count % 2 != 0))  //遇到黑色了要开始剪了
		{
			if (i - 1 > 0)
				position1[idx] = i - 1;
			else
				position1[idx] = i;
			count++;
			continue;
		}
		else if (pix < 2 && (count % 2 == 0))//遇到 白色剪的停止位置
		{
			if (i + 1 < width)
				position2[idx] = i + 1;
			else
				position2[idx] = i;
			count++;
			idx++;
		}

		//if (i > (width - 2) && (count % 2 != 0))  //前边有一半了,但是这后一半没找到
		//{
		//	
		//	position2[idx] = i;
		//	count++;
		//	idx++;
		//}

	}


	//记录所有字符的宽度
	for (int i = 0; i < idx; i++)
	{
		stringwidth[i] = position2[i] - position1[i];
		//	cout << "宽为:"<< stringwidth[i] << endl;
	}




	//Mat number_img = Mat(Scalar(0));
	//for (int i = 0; i < idx; i++) 
	//{
	//	Rect choose_rect(position1[i], 0, swidth[i], height);
	//	number_img = mat(choose_rect);
	//	imshow("number" + to_string(i), number_img);
	//
	//	// imwrite("number" + to_string(i) + ".jpg", number_img);
	//}

}



//找最小矩阵
void findminjuzhen(Mat src, pair<int, int>& num1, pair<int, int>& num2)
{


	int height = src.rows, width = src.cols;//赋值
	vector<int>hang(src.rows);
	vector<int>lie(src.cols);
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (src.at<uchar>(i, j) != 0)
			{
				hang[i]++;
				lie[j]++;
			}
		}
	}
	for (int i = 0; i < height; i++)
		if (hang[i] != 0)
			num1.second = i;    //最下界
	for (int i = 0; i < width; i++)
		if (lie[i] != 0)
			num2.second = i;
	for (int i = height - 1; i >= 0; i--)
		if (hang[i] != 0)
			num1.first = i; //最上界
	for (int i = width - 1; i >= 0; i--)
		if (lie[i] != 0)
			num2.first = i;




	cout << "(" << num1.first << " " << num1.second << ")";  //上下边界
	cout << " ";
	cout << "(" << num2.first << " " << num2.second << ")";//左右边界

}

//字符匹配
//首先是两张图作差
double imgcha(Mat inimg1, Mat mubanimg)
{
	//记录两张图不同的像素点的个数
	double difnum = 0;
	//cvtColor(mubanimg, mubanimg, COLOR_BGR2GRAY);
	//threshold(mubanimg, mubanimg, getThreshold( mubanimg), 255, THRESH_OTSU);  //模板二值化
	//同样大小的处理
	resize(inimg1, inimg1, Size(30, 55));
	resize(mubanimg, mubanimg, Size(30, 55));

	Mat temp0;
	absdiff(inimg1, mubanimg, temp0);
	for (int i = 0; i < temp0.rows; i++)
	{
		for (int j = 0; j < temp0.cols; j++)
		{
			difnum += temp0.at<uchar>(i, j);
		}
	}

	return difnum;  //返回不一样的值
}
typedef pair<double, int>PDL;
int pathnum = 0;


void splitSample(char ch, int k, Mat inputImg)
{
	string st = to_string(k) + ".jpg";
	//cout << st << endl;
	imwrite("F:\\erjixiangmu\\erjixiangmu\\muban2\\" + to_string(ch - 48) + "." + st, inputImg);

}
char recognition(Mat inputImg, int k)
{
	string sampleimgpathall = "muban";
	vector<String> sampleimgpath;
	glob(sampleimgpathall, sampleimgpath, false);//读取模板所有的路径,存到FN里面
	int sampleimgnum = sampleimgpath.size();
	vector<pair< double, int> >nums(sampleimgnum + 1);//i表示图片在路径vector里的下标 并存储该图片和模板里的图片的差
	for (int i = 0; i < sampleimgnum; i++) {

		Mat numImg = imread(sampleimgpath[i], 0);
		//大小同一
		resize(numImg, numImg, Size(40, 60));
		resize(inputImg, inputImg, Size(40, 60));
		nums[i].first = imgcha(inputImg, numImg);//不同像素值的差
		nums[i].second = i;//在迭代器中的下标
	}
	// imshow("图片", inputImg);
	waitKey();
	//排序 越小说明匹配度越高
	sort(&nums[0], &nums[sampleimgnum]);
	int index = nums[0].second; //读取模板里的该图片
	//截取模板的函数
	splitSample(sampleimgpath[index][sampleimgpathall.size() + 1], k, inputImg);
	return sampleimgpath[index][sampleimgpathall.size() + 1];

}


//图像锐化
Mat ToSharoen(Mat inputImage)
{
	Mat outputImage(inputImage.size(), inputImage.type());
	int cnel = inputImage.channels();
	int rows = inputImage.rows;
	int cols = (inputImage.cols - 1) * cnel;

	for (int row = 1; row < rows - 1; row++)
	{
		const uchar* previous = inputImage.ptr<uchar>(row - 1);
		const uchar* current = inputImage.ptr<uchar>(row);
		const uchar* next = inputImage.ptr<uchar>(row + 1);
		uchar* output = outputImage.ptr(row);
		for (int col = cnel; col < cols; col++)
		{
			output[col] = saturate_cast<uchar>(5 * current[col] - (previous[col] + current[col + 1] + current[col - 1] + next[col]));
		}
	}
	//namedWindow("锐化图", WINDOW_AUTOSIZE);
	//imshow("锐化图", outputImage);
	return outputImage;
}

// 图像锐化





int main()
{
	int imgsum = 0, rightimg = 0;
	int stringnum = 0, rightstringnum = 0;
	int errornum = 0;
	//读取ISBN图片
	string testimgpathall = "ISBN";
	vector<string>testimgpath;//存储单个图片的路径

	glob(testimgpathall, testimgpath, false);//读取函数
	int testimgsums = testimgpath.size();
	vector<string>errorpath(testimgsums);
	vector<int>yuzhi(testimgsums);
	//开始对每一个ISBN进行操作
	for (int testindex = 0; testindex < testimgsums; testindex++)
	{
		cout << "开始处理第" << testindex << "张照片" << endl;
		Mat src = imread(testimgpath[testindex]);

		//同一图片大小
		double width = 600;
		double height = width * src.rows / src.cols;
		resize(src, src, Size(width, height));
		//imshow("原图", src);

		Mat gary_src;
		cvtColor(src, gary_src, COLOR_BGR2GRAY);
		//imshow("灰度图", gary_src);

		Mat gary_sharoen = ToSharoen(gary_src);
		//imshow("锐化后的灰度图", gary_sharoen);
		// 
			//高斯去噪处理
		Mat gas;
		GaussianBlur(gary_sharoen, gas, Size(7, 7), 1, 1);
		//	imshow("高斯去噪后的灰度图", gas);
		waitKey();




		//二值化
		Mat binImg;
		int thethreshold = getThreshold(gas);
		cout << "阈值为:" << thethreshold << endl;
		//	THRESH_BINARY (白底黑字)、THRESH_BINARY_INV(黑底白字)
			//THRESH_TRUNC(很暗很暗)THRESH_OTSU
		if (thethreshold < 123)
			thethreshold = thethreshold;
		else
			thethreshold += 31;

		threshold(gas, binImg, thethreshold, 255, THRESH_BINARY_INV);

		//判断是白底还是黑底图
		int thethreshold2 = th(binImg);
		cout << "白点数:" << thethreshold2;
		if (thethreshold2 > 190000)
		{
			cout << "白底图";
			threshold(gas, binImg, thethreshold, 255, THRESH_BINARY);
		}
		else
			threshold(gas, binImg, thethreshold, 255, THRESH_BINARY_INV);


		//	imshow("二值化图", binImg);
		waitKey();
		//旋转
		Mat temp1 = Hough(binImg);



		//	imshow("二值化图片进行霍夫旋转", temp1);
		waitKey();




		//水平裁剪

		Mat shui_img;
		shui_img = splitrow(temp1);
		//	imshow("水平剪完的二值图", shui_img);
		waitKey();
		//侵蚀一下
			//shui_img = qinshi(shui_img);
			//imshow("水平寝室", shui_img);
		waitKey();


		//做列的分割
		int position1[100000];//第一次遇到白色的位置
		int position2[100000];//第二次遇到白色的位置
		int  swidth[1000];//记录字符宽
		int posidx = 0;

		//垂直裁剪
		splitCol(shui_img, position1, position2, swidth, posidx);
		//开始对每个数字进行处理

		string ans = "";
		Mat number_img = Mat(Scalar(0));
		for (int i = 4; i < posidx; i++)
		{
			//Mat subImg = Mat(shuiimg, Range(0, shuiimg.rows), Range(position1[i], position2[i]));
			//做列分割
			Rect choose_rect(position1[i], 0, swidth[i], shui_img.rows);
			number_img = shui_img(choose_rect);
			//	imshow("垂直投影的分割图" + to_string(i), number_img);
			waitKey();
			//找该数字的最小矩阵
			pair<int, int> num1;
			pair<int, int> num2;
			findminjuzhen(number_img, num1, num2);
			//imshow("最小矩阵", number_img);
			//waitKey();
			int numimgheight = num1.second - num1.first;
			int numimgwidth = num2.second - num2.first;
			if (numimgheight > numimgwidth / 2 && numimgwidth > 3 && numimgheight > 5)
			{
				Mat minImg = Mat(number_img, Range(num1.first, num1.second + 1), Range(num2.first, num2.second + 1));
				// imshow("最小矩形", minImg);
				//waitKey();
				//是数字或者字母
				char ch = recognition(minImg, testindex);
				//char ch = pipei(minImg);
				if (ch >= '0' && ch <= '9')
				{
					ans += ch;
					cout << ch << " ";
				}
			}



		}
		cout << endl;

		//现在开始对比
		cout << "现在的路径是:" << testimgpath[testindex] << endl;
		string rightans = "";
		for (int i = 0; i < testimgpath[testindex].length(); i++)
		{
			char temp = testimgpath[testindex][i];
			if (temp >= '0' && temp <= '9')
			{
				rightans += temp;
			}
		}

		cout << "正确的数据是:" << rightans << endl;
		cout << "读出来的答案是:" << ans << endl;
		stringnum += rightans.length();//总的字符数
		int ansidx = min(ans.length(), rightans.length());
		bool right = true;
		for (int i = 0; i < ansidx; i++)
		{
			if (ans[i] != rightans[i])
				right = false;
			else
				rightstringnum++;//答对的字符数				
		}
		if (ans.length() == rightans.length() && right)//识别正确
		{
			rightimg++;
			cout << "YES" << endl;
		}
		else
		{
			cout << "NO" << endl;
			cout << "-------------------------------------" << endl;

			errorpath[errornum] = testimgpath[testindex];
			errornum++;
		}

	}
	printf("正确个数:%4.d 正确率:%f\n", rightimg, rightimg * 1.0 / testimgsums);
	printf("准确个数:%4.d 准确率:%f\n", rightstringnum, rightstringnum * 1.0 / stringnum);



	for (int i = 0; i < errornum; i++)
		cout << "错误的路径是:" << errorpath[i] << endl;

	waitKey(0);

}