由于最近需要用SD卡记录摄像头拍的图像,记录的文件格式十六进制的(例如:0xf0就是对应图像中的八个像素点)需要做一个SD卡上位机来将十六进制文件转换成JPG图像格式,方便对图像的分析。
总体的思路是这样的
1.创建文件流,打开十六进制的文件
2.讲十六进制文件数据存放在一个数组中
3.读取数据,寻找事先设定的通讯协议(0x00,0xff,0x01,0x00)
4.安位解压数据,缓存在一个临时存放图片数据的数组中
5.将图像数据画在pictureBox上,编号进行保存(JPG格式)
6.放回到第三步继续执行,直到读取到文件尾部,即完成。
这里具体说说文件读取和JPG的保存
一、创建一个保存图片的文件夹
1.在窗口初始化时,默认在D盘创建一个总文件夹
string sPath = @"D:\解压图片";//默认在D盘创建一个文件夹,用于存放图片 if (!Directory.Exists(sPath)) { Directory.CreateDirectory(sPath); }
2.为了方便查看,按时间对文件夹分类
void CreatFile()//创建子文件夹 { PublicValue.SaveTime = DateTime.Now.ToString("yyyy年MM月dd日hh时mm分", DateTimeFormatInfo.InvariantInfo); string sPath = @"D:\\解压图片\\" + PublicValue.SaveTime; PublicValue.SavePath = @"D:\\解压图片\\" + PublicValue.SaveTime; if (!Directory.Exists(sPath)) { Directory.CreateDirectory(sPath);//创建存放图片的文件夹 } }
二、文件流的使用
//二进制读取 FileStream fs = new FileStream(PublicValue.OpenFileName, FileMode.Open); BinaryReader br = new BinaryReader(fs); int count = (int)fs.Length; PublicValue.FileLength =(int)fs.Length ;//文件长度 byte[] buffer1 = new byte[count]; //存放十六进制数据 br.Read(buffer1, 0, buffer1.Length); //直接读取全部文件到buffer1中(以十进制方式)偶数为数据 fs.Close();
最后,做出来的效果。
完整版程序:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 using System.Globalization; 11 using System.IO; 12 13 namespace WindowsFormsApplication1 14 { 15 public partial class Form1 : Form 16 { 17 private int num; 18 private byte[] buffer; //解压后的一维数组 19 private byte[,] img_all; //解压后的二维数组 20 21 Bitmap bitmap_original; 22 23 public Form1() 24 { 25 InitializeComponent(); 26 //变量初始化 27 but_deal.Enabled = false; 28 PublicValue.Width = int.Parse(text_width.Text); //设置宽度 29 PublicValue.Height = int.Parse(text_heigh.Text);//设置高度 30 buffer =new byte [PublicValue.Width *PublicValue .Height]; 31 img_all = new byte[PublicValue.Height, PublicValue.Width]; 32 bitmap_original = new Bitmap(PublicValue.Width, PublicValue.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 33 34 string sPath = @"D:\解压图片";//默认在D盘创建一个文件夹,用于存放图片 35 if (!Directory.Exists(sPath)) 36 { 37 Directory.CreateDirectory(sPath); 38 } 39 } 40 41 private void button1_Click(object sender, EventArgs e) 42 { 43 but_modfi.Enabled = false; 44 int width = PublicValue.Width ; 45 int height = PublicValue.Height; 46 //写文件 47 //StreamWriter sfile = new StreamWriter("D://sufei.text");//写入到sufei.text文件中 48 //sfile.Write("sufeifufei\n1212\nkjhdfgjhj"); 49 //sfile.Close(); 50 //二进制读取 51 FileStream fs = new FileStream(PublicValue.OpenFileName, FileMode.Open); 52 BinaryReader br = new BinaryReader(fs); 53 54 int count = (int)fs.Length; 55 PublicValue.FileLength =(int)fs.Length ;//文件长度 56 byte[] buffer1 = new byte[count]; //存放十六进制数据 57 byte[] buffer2 = new byte[count* 8]; //存放解压后的数据 58 br.Read(buffer1, 0, buffer1.Length); //直接读取全部文件到buffer1中(以十进制方式)偶数为数据 59 fs.Close(); 60 61 CreatFile();//创建文件夹(默认在D盘的“解压图片”目录下创建子文件夹) 62 63 //-------------分离图片-------------------------------------------------------------------------------- 64 if (count > (width * height / 8)) 65 { 66 for (int num = 0; num < (count - (width * height / 8)); ) 67 { //匹配4个通信协议 68 if (buffer1[num] == 0x00 && buffer1[num + 1] == 0xff && buffer1[num + 2] == 0x01 && buffer1[num + 3] == 0x00) 69 { 70 //解压 71 Jieya(buffer1, num + 4); 72 73 drawImage(); //标记图像 74 75 SavePicture(); //保存图片 76 77 num += 4 + (width * height / 8);//下一个 78 } 79 else { num++; } 80 } 81 } 82 83 } 84 85 private void button2_Click(object sender, EventArgs e) 86 { 87 openFileDialog1.Filter = "(*.txt)|*.txt"; 88 if(DialogResult.OK == openFileDialog1 .ShowDialog ()) 89 { 90 PublicValue.OpenFileName = openFileDialog1.FileName;//得到目标文件路径 91 but_deal.Enabled = true; //激活处理按钮 92 label2.Text = PublicValue.OpenFileName; //显示文件地址 93 } 94 text_heigh.Enabled = false; 95 text_width.Enabled = false; 96 // but_modfi.Enabled = false; 97 98 } 99 100 private void button1_Click_1(object sender, EventArgs e)//修改图片大小 101 { 102 MessageBoxButtons messButton = MessageBoxButtons.OKCancel; 103 DialogResult dr = MessageBox.Show("确定要修改吗?","提醒",messButton); 104 if(dr == DialogResult.OK)//选择确定 105 { 106 PublicValue.Width = int.Parse(text_width.Text); //设置宽度 107 PublicValue.Height = int.Parse(text_heigh.Text);//设置高度 108 buffer = new byte[PublicValue.Width * PublicValue.Height]; 109 img_all = new byte[PublicValue.Height, PublicValue.Width]; 110 bitmap_original = new Bitmap(PublicValue.Width, PublicValue.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 111 } 112 } 113 114 void buffer2bitmap_original() 115 { 116 for (int i = 0; i < PublicValue.Height; i++) 117 { 118 for (int j = 0; j < PublicValue.Width; j++) 119 { 120 Color color = Color.FromArgb(0, img_all[i, j], img_all[i, j], img_all[i, j]); //相当于直接把CCD数据描绘成图的颜色 121 bitmap_original.SetPixel(j, i, color); 122 } 123 } 124 } 125 delegate void delegate_drawPic(PictureBox pic, Bitmap bitmap); 126 void drawPic(PictureBox pic, Bitmap bitmap)//第一个参数 使我们用来刷图像的控件 第二个参数时我们选择的模式mode=0 是刷原始图像 mode=1 是刷二值化图像 127 { 128 if (pic.InvokeRequired) 129 { 130 delegate_drawPic d_drawPic = new delegate_drawPic(drawPic); 131 pic.Invoke(d_drawPic, new object[] { pic, bitmap }); 132 } 133 else 134 { 135 pic.Refresh();//图像控件刷新 136 pic.Image = bitmap;//显示图像 137 } 138 } 139 140 void drawImage() 141 { 142 buffer2bitmap_original(); 143 drawPic(pictureBox1, (Bitmap)bitmap_original.Clone()); //使用对象复制 可以解决两个线程同时使用一个资源的问题 144 } 145 146 void Jieya(byte [] buffer_temp,int begin_num) 147 { 148 byte[] colour; //0.1分别对应的颜色 149 colour = new byte[2] { 255, 0 }; 150 int dst = 0; 151 int srclen = (PublicValue.Width * PublicValue.Height) / 8; 152 byte tmpsrc = 0; 153 int tempscr = begin_num; 154 while (srclen > 0) 155 { 156 srclen--; 157 tmpsrc = buffer_temp[tempscr]; 158 tempscr++; 159 buffer[dst] = colour[(tmpsrc >> 7) & 0x01]; dst++; 160 buffer[dst] = colour[(tmpsrc >> 6) & 0x01]; dst++; 161 buffer[dst] = colour[(tmpsrc >> 5) & 0x01]; dst++; 162 buffer[dst] = colour[(tmpsrc >> 4) & 0x01]; dst++; 163 buffer[dst] = colour[(tmpsrc >> 3) & 0x01]; dst++; 164 buffer[dst] = colour[(tmpsrc >> 2) & 0x01]; dst++; 165 buffer[dst] = colour[(tmpsrc >> 1) & 0x01]; dst++; 166 buffer[dst] = colour[(tmpsrc >> 0) & 0x01]; dst++; 167 } 168 169 //一维数组转二维数组 把原始图像赋值给新的数组用于处理 170 for (int height = 0; height < PublicValue.Height; height++) 171 { 172 for (int weight = 0; weight < PublicValue.Width; weight++) 173 { 174 img_all[height, weight] = buffer[(height * PublicValue.Width) + weight]; 175 } 176 } 177 } 178 179 void SavePicture() 180 { 181 if (pictureBox1.Image != null) 182 { 183 pictureBox1.Image.Save(PublicValue.SavePath +"\\"+ PublicValue.pic_num.ToString()+".jpg"); 184 PublicValue.pic_num++;//进行编号 185 } 186 187 } 188 189 void CreatFile()//创建文件夹 190 { 191 PublicValue.SaveTime = DateTime.Now.ToString("yyyy年MM月dd日hh时mm分", DateTimeFormatInfo.InvariantInfo); 192 string sPath = @"D:\\解压图片\\" + PublicValue.SaveTime; 193 PublicValue.SavePath = @"D:\\解压图片\\" + PublicValue.SaveTime; 194 if (!Directory.Exists(sPath)) 195 { 196 Directory.CreateDirectory(sPath);//创建存放图片的文件夹 197 } 198 } 199 200 } 201 }