1. 实验室中CCD的实际色阶为14位,获取的原始图像数据的每个值都存储在一个字中,即存储色阶16位,也就是说最高两位的数据一直为0,同时获取的图片信息仅仅是16色阶的灰度图,而采用wxWidget没有办法直接将16位的数值串保存为图片格式,如tiff格式,那么如何将16位的数值串以图片的形式进行保存呢?
经过这么几天的折腾总算是找到了一条解决的途径,就是将16位的数值串转化为8为的数值串,也许你会很快的想到这么一个方法,nValue*max(uint8)/max(uint16);用来表示转化后的数值,不够还是得考虑一下CCD的实际色阶,由于是14位,因此可以采用这样的方式nValue*max(uint8)/max(uint14);不过由于我们对于图片的处理是直接对图片的原始数据进行处理,而转化只是图片在显示屏上显示的前提步骤,采用上述的方式虽然能够相对很准确的进行转化,但是需要花费一定的计算量,而通过近似的转化能够更快的进行这个转化过程,同时获取得到的图片依然具有较好的清晰度,下面细说一下我采用的方法:
1: unsigned short nPicData16 = new unsigned short[nBufSize]; // nBufSize is the size to store pic
2:
3: // to get the nPicData16
4: // ..................
5: // get the nPicData16
6:
7: char *pcPicData8 = new char[nBufSize];
8: for (size_t i = 0; i < nBufSize; ++i) {
9: pcPicData8[i] = (char)(nPicData16>>6);
10: }
11:
12:
由于2^6在2^14中所占的比例较小因此可以采用这样的近似的方法。(这种方法具体有什么作用或是缺陷还没有细究,请各位看官给点看法)
2. 顺利将14位数值串转化成为8为数值串后,尝试的使用下列方式进行图片保存,发现结果一片黑,数值都为0了:
1: // 结果发现存储得到的save.bmp图是24b的
2: wxBitmap bitmap(pcPicData8,1392,1040,8);
3: bitmap.SaveFile(wxT("save.bmp"),wxBITMAP_TYPE_BMP);
4:
因此猜想wxWidget对直接获取的数据串进行保存时采用的rgb的模式进行保存,可能只会保存为24字节格式的图片,也就是想要将图片显示到屏幕上时,也应该采用24b的图片。不过wxWidget对于图片数据却能够读取8位的图片,但是再次采用上述的方式进行存储时,变成了32字节的了,(各位大虾知不知道有没有方法能够直接保存8位图的呢)。
于是采用了将这个8位的数值串分别赋值给R,G,B,用这种方式实现灰度图的创建,然后再进行保存,最终解决了问题。
1: unsigned char *rgbData = new unsigned char[1392*1040*3];
2: unsigned char *ptr1 = (unsigned char*) pcPicData8;
3: unsigned char *ptr2 = rgbData;
4: for (int i = 0; i < 1392*1040; ++i) {
5: *ptr2++ = *ptr1;
6: *ptr2++ = *ptr1;
7: *ptr2++ = *ptr1++;
8: }
9: wxImage myImage(1392,1040,rgbData);
10: myImage.SaveFile(wxT("save.bmp"),wxBITMAP_TYPE_BMP);
从89年到现在,将近23个春秋了,人生的近三分之一已没入了历史的河流中,仿佛一颗尘埃掉入河中,泛不起一丝涟漪。这仅仅是一种不真实的感受,电影《蝴蝶效应》中讲述的就与此相反,过去那看似微末的行为,随着时间的流逝,却会被逐渐放大,带来预料之外的影响,但是通过比较,才能清楚的认清,变化的大小,而目前时间流淌的不可逆性,使得这样的情景注定只能够在荧屏上展现,在脑海中空旋。
再向前迈出两步就成为大学毕业的人了,四年的大学生涯也将随着落幕的钟声逐渐远去。但是,我觉得这四年中,我不是一个合格的掌舵人,只是顺应着波浪,一路中,风平浪静,就仿佛麦哲伦在从南美到菲律宾三个月的航行中,没有遇到一次波浪,算是一种运气吧。四年大学生涯的结束带给我的没有不舍,没有对未来更美好的憧憬,只有对于自己人生路途的茫然,而在武汉更能体会到内外茫然的同步效应^^。
小学6年,初中3年,高中3年,大学4年,随着教育的深入,仿佛感到自己正被某种莫名的东西慢慢的同化着、侵蚀着,从最初的活跃慢慢过度到了淡然的状态。这个深入学习的过程仿佛拥有着难以拒绝的“魔力”,不断的诱惑着你,慢慢的迷失了自己。
也许是深受中国古代教育模式的影响,目前虽然在推广以学生为主导,减负等措施,但是终究如晚霞般,慢慢的消失,随之而来的便是无尽的黑暗。难,改正一个习惯难,这是总所周知的,因此想要对历史积淀下来的东西进行改变更不是轻而易举的事情。这里并未有批判填鸭式、以课本为主的教育模式,想古代文人主要学习的书籍就那么基本,反复看的也就那么基本,在死记之后仍会不断地进行摸索、不断的温习,而后便会带来了悟,转化为自己的东西,而现在呢,知识的量相比较而言不知增加了多少倍,同时知识的更新速度更是猛蹿。死记了一部分知识,来未等有足够的时间将其消化,便掩埋在了新知识或是旧的不同的知识的沙泥中,忘记便是必然的事情。而学无所获的结果,更会促使内心滋生厌学的心态,恶性循环也成为大多数学生在经历的一种状态,心累身累,不如放下,沉溺与游戏中,寻找有所成就的快感。
同时有多少人是走着自己喜欢的道路,有多少人认清了自己想要走的道路呢?从儿时开始,由于自己的人生观,世界观没有很好的形成,从而家长、老师就成了重要的指路人,但是有些家长,将自己的认知自己的理解,认为就是孩子所需要的,于是各种的培训,各种的补习接踵而至,想让孩子成为邻里最出色的一名,相互的比较,用的便是各种的标签,“学生干部”,“成绩”,“奖状”等等。但是往往忽略孩子对于新鲜的事物总是充满这好奇,欢喜也许仅仅是一时的,但如果好好的引导,或许能够成为一种喜好,强加的压迫却往往适得其反,就算是能够获取所谓的成功,孩子的心中深藏的也许是更深的苦,难言而又长久。
高中步入大学前,首先需要选择的是具体的专业,但是哪个专业是你真的想要选择的呢,家长老师开始从就业情况,大纵好评度不断的给你分析,影响着你的选择,然后听从他们最终的判决,但是18岁,已经成年了的你们是否曾想过先充分认清楚自己的追求,然后进行选择呢?也许是小学、初中、高中这么步步走来的影响,我们已经习惯了从书中,从老师的口中,从家长的言语中寻求所谓的标准答案,不知道如何通过自身去辨识属于自己的方向,我们也慢慢失去了对于兴趣和爱好的感觉,就算迎面相见,也不曾相识,插肩而过,便成陌路客。原来一直都是借口,借口对前路的未知,借口他人比自己更了解自己,借口在其他人身上存在自己想要的标准答案,就算是自己的父母,有多少能够知道自己的孩子真正想要的是什么,他们的本意自然不坏,但是帮倒忙的可能也是存在的,并且不小。
也许是失去了警觉性,在意识到危险降临的时候,才会慌张,才会不知所措,才会瞎走瞎撞,后悔过后,依然一片晴朗。在没认清自己喜欢干些什么的时候,进入了大学,进入了一个所谓喜欢、所谓很好的专业,开始了大学生活。上着既定的课程,为了考试,打了兴奋剂般的复习,仿佛这一切都是为了成绩。一个流程的教学下来,对于悲喜的敏感性也越来越差,顺应着大流忙碌着,上课,游戏,考试等等。就算是那些实验性的课程也多是走走过场,便能轻松的通过。浑浑噩噩,只是不同的人,用不同的浑噩的方式,得到了不同的浑噩的结果,谁都不用羡慕谁,因为哪些所谓的牛人,也许也如你一般,并没有行走在内心所要的道路上,只是披了一件华丽的外衣,掩藏了内心深处的伤痕。
毕业之后会选择择业或是深造,很多都是无法离开现在既定的专业了,会想除了这,我还会些什么,是的,直到大学结束,我们有种思维正在根深蒂固,学到的知识能够决定自己人生的方向。而这知识的选择却并非是自己所想要的,只是错误的延续了下去。往往会忘记,获取知识的这种能力,因为没有单位能够给这种能力一个量化的指标,使得这种能力的拥有者也会在别人的反问中对自己产生越来越大的怀疑,这也是因为我们很少清楚的认识到它的存在,在实践中主动的运用它,只是在一种迷糊的状态下行动着,犹如雾里看花,除了朦胧还是朦胧,而后在错误中错误下去,到清醒之时已没有勇气去迎接真实的自己。把所有的固定的知识忘却,剩下的就是属于你的精华。知识是一种累积,一种沉淀,随着慢慢的积累总会体现出它的重量,但是智慧是一种方法,一种思维,能够使你懂得如何获取知识,如何运用它们,如何创造出带有自己鲜明特性的价值。
一路之中还有很多东西在不断的消失,还有勇气,指出是非对错的勇气,给出自己见解的勇气,承认错误的勇气,大声喊出爱的勇气。也许你会说,现在学得应该是我喜欢的,你也是加了应该两个字,说明内心之中有了动摇,而不够稳定坚固的地基之上是建造不出高楼大厦的。请先沉下心来深思,从过去,到现在,顺便望一望未来,也许有种触动会从内心深处蔓延开来。但是一旦确认了你的喜好,请鼓起勇气,大声的喊出自己的心声,坚定不移的走下去。
用一句也许不是很相关的话作为结语:
如果爱,请深爱!!
1: class Base
2: {
3: private:
4: int m_nValue;
5:
6: public:
7: Base(int nValue)
8: : m_nValue(nValue)
9: {
10: }
11:
12: protected:
13: void PrintValue() { cout << m_nValue; }
14: };
15:
16: class Derived: public Base
17: {
18: public:
19: Derived(int nValue)
20: : Base(nValue)
21: {
22: }
23:
24: // Base::PrintValue was inherited as protected, so the public has no access
25: // But we're changing it to public by declaring it in the public section
26: Base::PrintValue;
27: };
注意 Base::PrintValue; 该语句并没有添加()
摘要: from http://www.learncpp.com/cpp-tutorial/104-container-classes/ 1: #ifndef INTARRAY_H 2: #define INTARRAY_H 3: 4: #include <assert.h> // for assert() 5: 6: class IntArray 7:...
阅读全文
详细内容参见:http://www.wxwidgets.org/develop/standard.htm
以一个入门的新手来看,C++具有很大的灵活性,与技巧性,但是这些技巧性的东西可能带来的是代码可读性的降低,效率的不稳定,以及很多人对于C++的唾骂。本人理解,C++的灵活性是用来构建库的,而在具体项目运用中是在类库的一定限制规范下选择合适的库进行开发,这样开发效率和代码的可读性将大大提升。
理解可能有误,请拍板。
在使用wxwidget库编写时,
通常的C++规则(部分)
1. 不使用C++模版
2. 不使用C++异常
3. 不使用RTTI
4. 不使用命名空间
5. 不使用STL
6. 在for内部不进行变量的声明
7. 不使用嵌套类
8. 不使用新的逻辑关键字(or,and,not等)
9. 不使用全局变量
10. 将warnings打开,并消除warnings
11. 使用#if 0注释代码段
12. 避免重载虚函数
13. 避免使用额外的分号
wxWedget规则
1. 同一文件头部
/////////////////////////////////////////////////////////////////////////////
// Name: src/common/foo.cpp
// Purpose: Implementation of wxFoo
// Author: Your Name
// Created: 2006-12-03
// RCS-ID: $Id: standard.htm 1562 2012-01-08 11:38:14Z VZ $
// Copyright: (c) 2006 wxWidgets development team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
2. 用四个空格代替tab
3. public 然后 protected 然后 private
4. 使用wx作为公共符号
5. 文档中避免使用!
摘要: 原文 from www.learncpp.com/cpp-tutorial/88-constructors-part-ii/ 私有构造函数 偶尔,我们不想让用户在class外使用特殊的构造函数。为了实现这个想法,我们可以将构造函数设定为私有的。 1: class Book 2: { 3: private: 4: int m_nPages; 5: 6: ...
阅读全文
从开始学习C++到现在已经将近4年了,大一时上的课程就只讲了和C语言处理相同的部分,最为关键的面向对象编程却被无视了,接下去的两年半的时间也没有怎么接触过这门语言,直到大三下的时候才有种想续前缘的冲动,到现在断断续续的学习,没有什么项目,没有什么任务,进度不是很大。
也许作为新手的通病,经常会在大堆的书海中徘徊,看了这本,没看多久,有人说另一本更好,又拿起那本从头继续开始看,这样下来,只是在不断的重复着,却没有前进,或是前进的步伐慢到一时半刻难以察觉的地步。
现在通过写博客来督促自己,坚持下去,总会出现奇迹。
教程先紧抓一本,将其熟悉了再考虑是否继续换一本,当然作为一门编程语言,实践自然是必不可少的,看书之余,看看别人的代码,构思一下即将要做的小项目,拿几个问题练练手,如此才能更好的进步。
编程中一般出现的错误有两种:语法上的错误与语义上的错误,语法中的错误几乎都能够被编译器识别出来,但是语义上的错误编译器就无法识别,因此在编程的过程中应该时刻警惕语义错误的出现。
在编程初始,我们可以事先编写防错的程序段,一般错误会出现在什么地方呢?
1)函数调用时传递的参数的有效性
2)函数的返回值可能隐含了错误发生的可能
3)从用户或文件中读取的输入导致的错误
为了很好的避免这些错误,我们通常遵循如下的措施:
1)在函数的顶部,确保传递进来的参数有效
2)函数调用后,检测返回值
3)使输入的值有效,符合规范
那么选取怎样的方式对错误进行处理呢,一般如下:
1)快速跳过代码
1: void PrintString(char *strString)
2: {
3: // Only print if strString is non-null
4: if (strString)
5: std::cout << strString;
6: }
2)想调用程序中,返回错误码
1: int g_anArray[10]; // a global array of 10 characters
2:
3: int GetArrayValue(int nIndex)
4: {
5: // use if statement to detect violated assumption
6: if (nIndex < 0 || nIndex > 9)
7: return -1; // return error code to caller
8:
9: return g_anArray[nIndex];
10: }
3)如果你想在发现错误时直接终止程序,可以使用exit函数
1: int g_anArray[10]; // a global array of 10 characters
2:
3: int GetArrayValue(int nIndex)
4: {
5: // use if statement to detect violated assumption
6: if (nIndex < 0 || nIndex > 9)
7: exit(2); // terminate program and return error number 2 to OS
8:
9: return g_anArray[nIndex];
10: }
4)如果用户输入不合理的值,就继续要求输入
1: char strHello[] = "Hello, world!";
2:
3: int nIndex;
4: do
5: {
6: std::cout << "Enter an index: ";
7: std::cin >> nIndex;
8: } while (nIndex < 0 || nIndex >= strlen(strHello));
9:
10: std::cout << "Letter #" << nIndex << " is " << strHello[nIndex] << std::endl;
5)可以使用cerr输出错误,在gui编程的时候,可以直接在遇到错误的时候跳出对话框,输出错误码,然后终止
1: void PrintString(char *strString)
2: {
3: // Only print if strString is non-null
4: if (strString)
5: std::cout << strString;
6: else
7: std::cerr << "PrintString received a null parameter";
8: }
另,可以使用assert
1: int g_anArray[10]; // a global array of 10 characters
2:
3: #include <cassert> // for assert()
4: int GetArrayValue(int nIndex)
5: {
6: // we're asserting that nIndex is between 0 and 9
7: assert(nIndex >= 0 && nIndex <= 9); // this is line 7 in Test.cpp
8:
9: return g_anArray[nIndex];
10: }
看到一篇比较有意思的文章,在这里就翻译一下,当今天发表的内容了。
from http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/
一个程序对于内存的使用,一般可以分为四类:
1. 代码区域,通过的编译的程序在代码中存储的位置
2. 全局变量区域,全局变量存储的位置
3. 堆,动态内存分配的变量存储的位置
4. 栈,函数参数和局部变量存储的位置
下面将主要针对3,4两个方面进行论述。
堆
堆是一个用于动态分配的很大的内存池。在C++中,当你使用new操作符分配内存时,这个内存是从堆中取得的。
1: int *pValue = new int; // pValue is assigned 4 bytes from the heap
2: int *pArray = new int[10]; // pArray is assigned 40 bytes from the heap
因为,要分配的内存的准确位置事先是不知道的,所以分配的内存是间接获取的,也就说明了为什么new操作符返回的是指针。这里你并不需要担心背后内存具体如何分配的机制。但是,有一点值得明了,连续的内存请求所指向的很可能不是连续的地址的内存片段。如:
1: int *pValue1 = new int;
2: int *pValue2 = new int;
3: // pValue1 and pValue2 may not have sequential addresses
上例中,两个new是连续的,但是分配得到的pValue1和pValue2的地址是不连续的。当动态分配的变量被删除后,内存有被返回到堆中以备后续中再次被动态分配。
堆有如下优缺点:
1. 分配的内存一直处于被分配的状态,知道去分配操作出现,才回到初始状态(没有及时去分配,如new后没有用delete,会导致内存的泄漏)。
2. 动态分配的内存必须通过指针联系
3. 由于堆是一个很大的内存池,大的数组,结构,类都应该在这里分配得到内存
栈
栈调用扮演了一个很有趣的角色。在我们讨论栈调用之前,让我们讨论一下什么叫做栈。
想象一下自助餐厅中的一堆叠起来的盘子。因为每个盘子都比较重,它们被叠起来的,你只能做以下三件事情。
1)看向最上面的盘子
2)将最上面的盘子拿掉
3)在上面放一个新的盘子
在计算机编程中,栈是一个存储其他变量的容器(很像一个数组)。但是,一个数组能够以你想要的方式任意更改获取其中的元素,栈则有更多的限制,栈中能够进行的操作如下:
1)查看栈顶的项
2)将栈顶的项从顶部移除
3)将一个新的项放置顶部
栈是后进先出(LIFO)的数据结构。
(略掉一些内容······)
我们主要来看当调用函数是栈发生了一些什么行为。
1)发生函数调用处的相关指令的地址被push进栈中
2)函数返回类型置于栈中,设置一个占位符
3)CPU跳至函数的代码中
4)现在栈顶的内容是一个特殊指针,栈帧。随后所有的加入到栈中的内容都是该函数的局部信息。
5)所有的函数参数都被放入栈中
6)函数中的指令得到执行
7)函数中的局部变量push栈中
当函数结束的时候,发生如下事件:
1)函数的返回值拷贝进入一个占位符中,
2)在栈帧之后的所有内容都被pop off,所有的局部变量都被销毁
3)返回值被pop off并赋值给函数中的变量,如果调用函数的返回值没有赋值给任何东西,该值就会丢失
4)下一个语句的地址从栈中pop off,CPU继续执行
栈溢出
栈的大小是有限的,只能有序的容纳一定量的信息。如果程序试图向栈中放入过多的信息,栈将会溢出。栈溢出发生在栈的内存都被分配完了,那种情况下,更多的分配,将会发生在内存的其它片段中。
栈溢出通常发生在分配了太多的变量到栈上,或太多的嵌套函数调用,导致结果就是程序的奔溃。
如:
1: int main()
2: {
3: int nStack[100000000];
4: return 0;
5: }
栈的优缺点:
* 栈中的内容可以一直保留到pop off发生
* 编译时,栈中分配的内存是已知的,因此,可以直接通过变量访问内存。
* 因为栈相对而言是比较小的,所以小心会吃掉很多栈空间的事情。包括大型数组,结构体,类过多的内嵌,过多的递归等。