• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            讀《計算機科學概論》-1. 數據存儲-總結

                 摘要: 我們首先要學習的是在計算機科學中信息如何編碼和存儲。第一步,我們要討論計算機數據存儲設備的基礎知識,然后進一步研究如何進行信息編碼并存儲到系統內部。我們還將探討現如今數據存儲系統的各個分支,以及如何用數據壓縮、糾錯等技術來克服其不足。  閱讀全文

            posted @ 2012-07-08 22:10 鐘謝偉 閱讀(1298) | 評論 (0)編輯 收藏

            【轉】static_cast、dynamic_cast、reinterpret_cast和const_cast之間的區別

            原文出處

            C-style cast舉例:

             int i;

             double d;

             i = (int) d;

             

            上面的代碼就是本來為double類型的d,通過(int)d將其轉換成整形值,并將該值賦給整形變量i (注意d本身的值并沒有發生改變)。這就是典型的c-style類型轉換。

             

            下面是一個簡單的程序:

            #include <iostream>

            using namespace std;

             

            int main(void)

            {

                     int i;

                     double d = 11.29;

             

                     i = (int)d;

                     cout << i << endl;

                     cout << d << endl;

             

                     return 0;

            }

            輸出結果:

            11

            11.29

             

            我們發現d值本身并沒有發生任何變化。

             

            在簡單的情況下,上面這種類型轉換可以很好地工作,但在C++中往往還是不夠的,為此ANSI-C++新標準定義的四個轉換符,即static_castdynamic_castreinterpret_castconst_cast。同時在C++環境中,原先的C-Style的類型轉換仍舊可以使用。

             

            1) static_cast

                用法:static_cast <typeid> (expression)

                說明:該運算符把expression轉換為typeid類型,但沒有運行時類型檢查來確保轉換的安全性。

                用途:

                a) 用于類層次結構中基類和派生類之間指針或者引用的轉換。up-casting (把派生類的指針或引用轉換成基類的指針或者引用表示)

                安全的;down-casting(把基類指針或引用轉換成子類的指針或者引用)是不安全的。

                b) 用于基本數據類型之間的轉換,如把int轉換成char,這種轉換的安全性也要由開發人員來保證。

                c) 可以把空指針轉換成目標類型的空指針(null pointer)

                d) 把任何類型的表達式轉換成void類型。

                注意: static_cast不能轉換掉expressionconstvolitale或者__unaligned屬性。

             

            2) dynamic_cast

                用法:dynamic_cast <typeid> (expression)

                說明:該運算符把expression轉換成typeid類型的對象。typeid必須是類的指針、類的引用或者void*。如果typeid是類的指針類型,

                    那么expression也必須是指針,如果typeid是一個引用,那么expression也必須是一個引用。一般情況下,dynamic_cast

                    于具有多態性的類(即有虛函數的類)的類型轉換。

             

                           dynamic_cast依賴于RTTI信息,其次,在轉換時,dynamic_cast會檢查轉換的source對象是否真的可以轉換成target類型,

                   這種檢查不是語法上的,而是真實情況的檢查。先看RTTI相關部分,通常,許多編譯器都是通過vtable找到對象的RTTI信息

                   的,這也就意味著,如果基類沒有虛方法,也就無法判斷一個基類指針變量所指對象的真實類型,這時候,dynamic_cast只能

                   用來做安全的轉換,例如從派生類指針轉換成基類指針。而這種轉換其實并不需要dynamic_cast參與。也就是說,dynamic_cast

                   是根據RTTI記載的信息來判斷類型轉換是否合法的。

             

               用途:主要用于類層次之間的up-castingdown-casting,還可以用于類之間的交叉轉換。在進行down-casting時,dynamic_cast

                    具有類型檢查的功能,比static_cast更安全。檢測在運行時進行。如果被轉換的指針不是一個被請求的有效完整的對象指針,

                    返回值為NULL。當用于多態類型時,它允許任意的隱式類型轉換以及相反過程。不過,與static_cast不同,在后一種情況里

                    (注:即隱式轉 換的相反過程),dynamic_cast會檢查操作是否有效。也就是說,它會檢查轉換是否會返回一個被請求的有

                    效的完整對象。

                注意:dynamic_cast不能轉換掉expressionconstvolitale或者__unaligned屬性。

             

            3)   reinterpret_cast

                 用法:reinterpret_cast <typeid>(expression)

                 說明:轉換一個指針為其他類型的指針,也允許將一個指針轉換為整數類型,反之亦然。這個操作符能夠在非相關的類型之間進行

                    轉換。操作結果只是簡單的從一個指針到別的指針的值的二進制拷貝,在類型之間指向的內容不做任何類型的檢查和轉換。這

                    是一個強制轉換。使用時有很大的風險,慎用之。

                 注意:reinterpret _cast不能轉換掉expressionconstvolitale或者__unaligned屬性。

             

            4)   const_cast

                 用法:const_cast<typeid>(expression)

                 說明:這個類型操縱傳遞對象的const屬性,或者是設置或者是移除。如:

                       Class C{…}

                       const C* a = new C;

                       C* b = const_cast<C*>(a);

                       如果將上面的const_cast轉換成其他任何其他的轉換,編譯都不能通過,出錯的信心大致如下:

                       “…cannot convert from 'const class C *' to 'class C *'”

              

                 下面的代碼是4casting方法的典型用法示例:

                 #include <iostream>

                 using namespace std;

             

                 class Base

                 {

                 public:

                     int _base;

                     virtual void printinfo()

                     {

                          cout << _base << endl;

                     }

                 };

             

                 class Derived : public Base

                 {

                 public:

                     int _derived;

                     virtual void printinfo()

                     {

                          cout << _derived << endl;

                     }

                 };

             

                 int main(void)

                 {

                     Base b1;

                     Derived d1;

                     int aInt = 10;

                     long aLong = 11;

                     float aFloat = 11.11f;

                     double aDouble = 12.12;

             

                     Derived* pd = static_cast<Derived*>(&b1);                           // down-casting          不安全

                     Base* pb = static_cast<Base*>(&d1);                                   // up-casting                安全

                     Derived& d = static_cast<Derived&>(b1);                             // down-casting          不安全

                     Base& b = static_cast<Base&>(d1);                                      // up-casting                安全

             

                     aInt = static_cast<int>(aFloat);                                                // 基本數據類型轉換

                     void* sth = static_cast<void*>(&aDouble);                            // double指針類型轉換成void指針類型

                     double* bDouble = static_cast<double*>(sth);                    // void指針類型轉換成double指針類型

                     cout << *bDouble << endl;

             

                     Base* pb1 = dynamic_cast<Base*>(&d1);

                     //Derived* pd1 = dynamic_cast<Derived*>(&b1);                 // 編譯時有warning,運行時出錯

             

                     int bInt = reinterpret_cast<int>(pb1);                                       // 將地址或指針轉換成整數

                     cout << bInt << endl;

                     pb1 = reinterpret_cast<Base*>(bInt);                                     // 將整數轉換成地址或指針

             

                     int* cInt = reinterpret_cast<int*>(&aFloat);                             // 這個轉換的結果會出乎意料

                     cout << (int)*cInt << endl;

             

                     const Base* bBase = new Base();

                     Base* cBase = const_cast<Base*>(bBase);

                     //Base* dBase = dynamic_cast<Base*>(bBase);                // 不能通過編譯

                     //Base* eBase = static_cast<Base*>(bBase);                     // 不能通過編譯

                     //Base* fBase = reinterpret_cast<Base*>(bBase);             // 不能通過編譯

             

                     return 0;

            }

            posted @ 2012-07-07 10:06 鐘謝偉 閱讀(1159) | 評論 (1)編輯 收藏

            【轉】詳解C中volatile關鍵字

            原文

            volatile提醒編譯器它后面所定義的變量隨時都有可能改變,因此編譯后的程序每次需要存儲或讀取這個變量的時候,都會直接從變量地址中讀取數 據。如果沒有volatile關鍵字,則編譯器可能優化讀取和存儲,可能暫時使用寄存器中的值,如果這個變量由別的程序更新了的話,將出現不一致的現象。 下面舉例說明。在DSP開發中,經常需要等待某個事件的觸發,所以經常會寫出這樣的程序:
            short flag;
            void test()
            {
            do1();
            while(flag==0);
            do2();
            }

                這段程序等待內存變量flag的值變為1(懷疑此處是0,有點疑問,)之后才運行do2()。變量flag的值由別的程序更改,這個程序可能是某個硬件中 斷服務程序。例如:如果某個按鈕按下的話,就會對DSP產生中斷,在按鍵中斷程序中修改flag為1,這樣上面的程序就能夠得以繼續運行。但是,編譯器并 不知道flag的值會被別的程序修改,因此在它進行優化的時候,可能會把flag的值先讀入某個寄存器,然后等待那個寄存器變為1。如果不幸進行了這樣的 優化,那么while循環就變成了死循環,因為寄存器的內容不可能被中斷服務程序修改。為了讓程序每次都讀取真正flag變量的值,就需要定義為如下形 式:
            volatile short flag;
                需要注意的是,沒有volatile也可能能正常運行,但是可能修改了編譯器的優化級別之后就又不能正常運行了。因此經常會出現debug版本正常,但是 release版本卻不能正常的問題。所以為了安全起見,只要是等待別的程序修改某個變量的話,就加上volatile關鍵字。

            volatile的本意是“易變的”
                  由于訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優化。比如:
            static int i=0;
            int main(void)
            {
            ...
            while (1)
            {
            if (i) do_something();
            }
            }
            /* Interrupt service routine. */
            void ISR_2(void)
            {
            i=1;
            }
                程序的本意是希望ISR_2中斷產生時,在main當中調用do_something函數,但是,由于編譯器判斷在main函數里面沒有修改過i,因此可 能只執行一次對從i到某寄存器的讀操作,然后每次if判斷都只使用這個寄存器里面的“i副本”,導致do_something永遠也不會被調用。如果變量 加上volatile修飾,則編譯器保證對此變量的讀寫操作都不會被優化(肯定執行)。此例中i也應該如此說明。
                一般說來,volatile用在如下的幾個地方:
            1、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;
            2、多任務環境下各任務間共享的標志應該加volatile;
            3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;
            另外,以上這幾種情況經常還要同時考慮數據的完整性(相互關聯的幾個標志讀了一半被打斷了重寫),在1中可以通過關中斷來實現,2中可以禁止任務調度,3中則只能依靠硬件的良好設計了。
            二、volatile 的含義
                 volatile總是與優化有關,編譯器有一種技術叫做數據流分析,分析程序中的變量在哪里賦值、在哪里使用、在哪里失效,分析結果可以用于常量合并,常量傳播等優化,進一步可以死代碼消除。但有時這些優化不是程序所需要的,這時可以用volatile關鍵字禁止做這些優化,volatile的字面含義是易變的,它有下面的作用: 
             1 不會在兩個操作之間把volatile變量緩存在寄存器中。在多任務、中斷、甚至setjmp環境下,變量可能被其他的程序改變,編譯器自己無法知道,volatile就是告訴編譯器這種情況。
            2 不做常量合并、常量傳播等優化,所以像下面的代碼:
            volatile int i = 1;
            if (i > 0) ...
            if的條件不會當作無條件真。 
            3 對volatile變量的讀寫不會被優化掉。如果你對一個變量賦值但后面沒用到,編譯器常常可以省略那個賦值操作,然而對Memory Mapped IO的處理是不能這樣優化的。 
                前面有人說volatile可以保證對內存操作的原子性,這種說法不大準確,其一,x86需要LOCK前綴才能在SMP下保證原子性,其二,RISC根本不能對內存直接運算,要保證原子性得用別的方法,如atomic_inc。 
                對于jiffies,它已經聲明為volatile變量,我認為直接用jiffies++就可以了,沒必要用那種復雜的形式,因為那樣也不能保證原子性。 
                你可能不知道在Pentium及后續CPU中,下面兩組指令 
            inc jiffies 
            ;;
            mov jiffies, %eax
            inc %eax
            mov %eax, jiffies
            作用相同,但一條指令反而不如三條指令快。
            三、編譯器優化 → C關鍵字volatile → memory破壞描述符zz

                “memory”比較特殊,可能是內嵌匯編中最難懂部分。為解釋清楚它,先介紹一下編譯器的優化知識,再看C關鍵字volatile。最后去看該描述符。 
            1、編譯器優化介紹 
                 內存訪問速度遠不及CPU處理速度,為提高機器整體性能,在硬件上引入硬件高速緩存Cache,加速對內存的訪問。另外在現代CPU中指令的執行并不一 定嚴格按照順序執行,沒有相關性的指令可以亂序執行,以充分利用CPU的指令流水線,提高執行速度。以上是硬件級別的優化。再看軟件一級的優化:一種是在 編寫代碼時由程序員優化,另一種是由編譯器進行優化。編譯器優化常用的方法有:將內存變量緩存到寄存器;調整指令順序充分利用CPU指令流水線,常見的是重新排序讀寫指令。對 常規內存進行優化的時候,這些優化是透明的,而且效率很好。由編譯器優化或者硬件重新排序引起的問題的解決辦法是在從硬件(或者其他處理器)的角度看必須 以特定順序執行的操作之間設置內存屏障(memory barrier),linux 提供了一個宏解決編譯器的執行順序問題。 
            void Barrier(void)
                 這個函數通知編譯器插入一個內存屏障,但對硬件無效,編譯后的代碼會把當前CPU寄存器中的所有修改過的數值存入內存,需要這些數據的時候再重新從內存中讀出。 
            2、C語言關鍵字volatile 
                 C語言關鍵字volatile(注意它是用來修飾變量而不是上面介紹的__volatile__)表明某個變量的值可能在外部被改變,因此對這些變量的 存取不能緩存到寄存器,每次使用時需要重新存取。該關鍵字在多線程環境下經常使用,因為在編寫多線程的程序時,同一個變量可能被多個線程修改,而程序通過 該變量同步各個線程,例如: 
            DWORD __stdcall threadFunc(LPVOID signal)
            {
            int* intSignal=reinterpret_cast<int*>(signal);
            *intSignal=2;
            while(*intSignal!=1)
            sleep(1000);
            return 0;
            }
                 該線程啟動時將intSignal 置為2,然后循環等待直到intSignal 為1 時退出。顯然intSignal的值必須在外部被改變,否則該線程不會退出。但是實際運行的時候該線程卻不會退出,即使在外部將它的值改為1,看一下對應 的偽匯編代碼就明白了: 
            mov ax,signal
            label:
            if(ax!=1)
            goto label
                 對于C編譯器來說,它并不知道這個值會被其他線程修改。自然就把它cache在寄存器里面。記住,C 編譯器是沒有線程概念的!這時候就需要用到volatile。volatile 的本意是指:這個值可能會在當前線程外部被改變。也就是說,我們要在threadFunc中的intSignal前面加上volatile關鍵字,這時 候,編譯器知道該變量的值會在外部改變,因此每次訪問該變量時會重新讀取,所作的循環變為如下面偽碼所示: 
            label:
            mov ax,signal
            if(ax!=1)
            goto label
            3、Memory 
                  有了上面的知識就不難理解Memory修改描述符了,Memory描述符告知GCC: 
            1)不要將該段內嵌匯編指令與前面的指令重新排序;也就是在執行內嵌匯編代碼之前,它前面的指令都執行完畢
            2)不要將變量緩存到寄存器,因為這段代碼可能會用到內存變量,而這些內存變量會以不可預知的方式發生改變,因此GCC插入必要的代碼先將緩存到寄存器的變量值寫回內存,如果后面又訪問這些變量,需要重新訪問內存。
                 如果匯編指令修改了內存,但是GCC 本身卻察覺不到,因為在輸出部分沒有描述,此時就需要在修改描述部分增加“memory”,告訴GCC 內存已經被修改,GCC 得知這個信息后,就會在這段指令之前,插入必要的指令將前面因為優化Cache 到寄存器中的變量值先寫回內存,如果以后又要使用這些變量再重新讀取。 
                 使用“volatile”也可以達到這個目的,但是我們在每個變量前增加該關鍵字,不如使用“memory”方便。

            posted @ 2012-07-07 09:57 鐘謝偉 閱讀(1009) | 評論 (0)編輯 收藏

            wxWidget實現連續繪圖并能夠控制繪圖的開始與結束

                 摘要: 在用CCD相機拍照的圖像進行實時成像的時候遇到這么一個問題: 1: RunCamera(); 2: while (1) { 3: GetImg(); 4: ShowImg(); 5: } 6: CloseCamera(); 想要對獲取的圖像進行實時成像,最先想到的是采用while(1)的方式,但是這樣的方式會帶來一些問題,除了終止程序,沒有辦法使得循環...  閱讀全文

            posted @ 2012-07-06 11:17 鐘謝偉 閱讀(1524) | 評論 (0)編輯 收藏

            codelite悲劇了

            拾起才一個月的時間,codelite在今晚這個時候開機突然間無法打開了,開啟了后在任務管理器中會出現codelite,然后過一會兒就自動消失了,悲劇呀,算了還是用code::block了,最討厭的是莫名奇妙的錯誤,讓人不知所措誒

            posted @ 2012-07-05 19:44 鐘謝偉 閱讀(414) | 評論 (1)編輯 收藏

            CCD camera類設計及簡易實現

                 摘要: 上一篇文章中介紹了關于CCD camera實現的一般流程CCD camera的一般控制流程及些許困惑,現在想用類來實現這個過程。該類設計以及實現的目的是用于相機拍照,成像,存儲。目前僅考慮拍照與實時成像兩個過程。由于從簡單上進行設計,實現的一般流程中的一些步驟能夠省略。具體代碼如下: 1: // ccd_class.h 2: class CCDClass 3: { 4: pri...  閱讀全文

            posted @ 2012-07-04 11:16 鐘謝偉 閱讀(1021) | 評論 (0)編輯 收藏

            CCD camera的一般控制流程及些許困惑

            1. 聲明變量

            PCO_General        strGeneral;

            PCO_CameraType strCamType;

            PCO_Sensor         strSensor;

            PCO_Description   strDescription;

            PCO_Timing         strTiming;

            PCO_Storage       strStorage;

            PCO_Recording    strRecording;

            2. 設置變量大小

            strGeneral.wSize = sizeof(strGeneral);
            strGeneral.strCamType.wSize = sizeof(strGeneral.strCamType);
            strCamType.wSize = sizeof(strCamType);
            strSensor.wSize = sizeof(strSensor);
            strSensor.strDescription.wSize = sizeof(strSensor.strDescription);
            strSensor.strDescription2.wSize = sizeof(strSensor.strDescription2);
            strDescription.wSize = sizeof(strDescription);
            strTiming.wSize = sizeof(strTiming);
            strStorage.wSize = sizeof(strStorage);
            strRecording.wSize = sizeof(strRecording);

            3. 打開相機,填寫變量結構

            PCO_OPENCAMERA(&hCam, iBoardNumber)

            PCO_GETGENERAL(hCam, &strGeneral)

            PCO_GETCAMERATYPE(hCam, &strCamType)

            PCO_GETSENSORSTRUCT(hCam, &strSensor)

            PCO_GETCAMERADESCRIPTION(hCam, &strDescription)

            PCO_GETTIMINGSTRUCT(hCam, &strTiming)

            PCO_GETRECORDINGSTRUCT(hCam, &strRecording)

            4. 設置相機相關參數,曝光時間,觸發模式,ROI區域大小等

            5. arm the camera使相機準備好

            6. 獲取圖片大小,分配buffer

            PCO_GETSIZES(hCam, &actualsizex, &actualsizey, &ccdsizex, &ccdsizey)

            PCO_ALLOCATEBUFFER(hCam, &bufferNr, actualsizex*actualsizey*sizeof(WORD), &data, &hEvent)

            其中bufferNr是buffer的編號,actualsizex*actualsizey*sizeof(WORD)為data的大小,data用來存儲圖片數據。

            7. 開始進行記錄,并將圖片數據添加到指定的buffer中

            PCO_SetRecordingState(hCam,0x0001);

            PCO_AddBufferEx(hCam,0,0,bufferNr,actualsizex,actualsizey,bitres);

            原來不清楚data中的圖片數據是怎么獲取的,本來想將這個困惑寫到這里,不過寫著寫著突然發現原來如此,它是通過bufferNr來制定第六步中分配相應大小的data的。寫博客還是能夠把問題給理清楚一點的。

            8. 顯示圖像

            這里可以采用原來的文章中提到的方法使用wxWidget中遇到的圖片存儲問題一二

            9. 停止記錄

            PCO_SetRecordingState(hCam,0x000);

            10. 從CamRAM中讀取圖片

            PCO_GetNumberOfImagesInSegment(hCam, wActSeg, &dwValidImageCnt, &dwMaxImageCnt);

            PCO_GetImageEx(hCam,wActSeg,dw1swImage,dwLastImage,bufferNr,actualsizex,actualsizey,bitres)

            上述函數的應該與AddBufferEx有類似的功能。AddBufferEx直接在記錄過程中將數據存儲在data中,而GetImageEx是從ccd的寄存器中讀取相應的數據賦值到data中。

            11. 釋放用于存儲圖像數據的buffer,關閉相機

            PCO_FreeBuffer(hCamera,sBufNr)

            PCO_CloseCamera(hCamera);

             

            上面的過程是獲取單個圖像的整個流程,如果要連續進行拍攝呢?思考中。。。。。。

            posted @ 2012-07-02 17:42 鐘謝偉 閱讀(1276) | 評論 (0)編輯 收藏

            小數的存儲——選自《計算機科學概論》

            這本書對于入門級的人來說是一個不錯的選擇,它囊括了很多關于計算機方面的知識,能夠使你對這方面的知識有個廣泛的了解。

            對于小數的存儲常用的是浮點記數法。

            浮點記數法簡介

            對于知識的掌握,通過例子的學習是一個很好的方式。為了考慮到例子的簡易型,用一個字節來存儲浮點數。那么如01101011這樣的二進制序列表示的是什么小數呢?

            一個字節中浮點記數法有如下成分:

            image

            在01101011這么一個串中,符號位是0表示非負,1則表示負,指數為110,表示位數將乘以2^(指數),也就是將小數點從尾數位的最左邊移動指數個位,如果指數為正,向右移動;反之,向左移動指數位。110是用余碼的方式進行記錄的。對于余碼,我采用的解析的方式是,將最高為取反,按照補碼的方式進行讀取。

            110--->010,表示2;0100--->1100,表示-4;

            既然提到了補碼,就解釋一下補碼,最高位為零的補碼其值直接讀取,0110--->6;最高為為1的補碼,其值的讀取方式,從右往左遇到第一個1之后的所有位取反,讀出值后加個負號,1101--->0011,則-3。當然對于0和最小的負數,不適合上述的方式,但是也很容易就能給出其值。

            再讓我們回到0,110,1011這個串中,尾數.1011最左斷含有一個小數點,由于110--->2,因此小數點向右移動兩位則10.11,此時讀取值2+1/2+1/4=2又3/4。

            至此,我們已經知道小數是如何存儲在二進制串中,也知道了如何將其轉換為10進制數值,那么該提出注意事項的時候了。

            1. 規范化形式

                尾數最左端的一位必須是1,否則會出現多意的現象。如00111100,01000110,都可以解碼為3/8。

            2. 截斷誤差

                整型值會出現溢出現象,同樣浮點數也會出現類似的現象。如利用一字節浮點記數法存儲值2又5/8,先用二進制進行表示10.101,而尾數只有4位,因此會出現截斷。

                還有一個需要注意的是浮點記數法表示的數值加法中,它們相加的順序很重要。

                如,2+1/4+1/8+1/8+1/8+1/8,當到2(5/8)+1/8時,2(5/8)用二進制表示為10.101,這將發生截斷,變成10.10,繼續加1/8則會持續階段。當反過來進行加法運算時,則不會出現截斷的現象。

             

            由于實際浮點數具有較長的位數,能夠較好的運用于一般的浮點數運算中。但是這樣的問題在一些應用中是很嚴重的(如航海系統),小的誤差在不斷的加法運算中累加,最終產生嚴重的后果,因此對于精度要求較好的運算中,可以選擇采用分數表示法,分裝一個表示分數的類。

            posted @ 2012-06-30 20:50 鐘謝偉 閱讀(1234) | 評論 (0)編輯 收藏

            科研級CCD照相機簡介(1)——圖像顯示存儲、曝光、觸發

            工作學習上由于需要編寫一個能夠控制CCD進行拍照的簡易軟件,因此需要對CCD照相機的基本原理有一個較為清楚的認識,于是參考DICAM-PRO Operating Instructions寫下了這篇文章。

            QQ截圖20120629201447

            上圖顯示了CCD相機不同的功能模塊,其中主要的是Image Intensifier,CCD,12 Bit A/D,parallel/serial Converter,Logic Control。

            那么在計算機內部相對應的軟件是如何對從CCD相機傳輸進來的數據進行處理的呢。如下圖所示:

            image

             

            可見對于圖片數據進行存儲的時候可以采用16bit的形式進行無損存儲,但是在pc機的屏幕上進行顯示的時候,一般需將16bit的數組轉化為8bit的數組,然后采用8bit,24bit或32bit的形式將圖形成像到屏幕上。由于屏幕成像的方式是采用RGB或加一個alpha通道進行成像的,即使采用8bit的方式進行成像,也是將其轉化成了R=G=B的灰度圖進行成像。

            下面主要從CCD相機圖像增強,曝光、觸發方式兩個方面進行闡述。

            1. 圖像增強

            image

            光子打到光電陰極上產生電子,通過MCP進行增益而后打到熒光粉上發出光。

            該處需要注意的是:光子打到光電陰極上與CCD的使用壽命直接相關,另外,不允許強光照射到光電陰極板,這樣有可能損壞光電陰極板,從而使CCD相機損壞。由于對光強有一定的要求,因此對于曝光時間也要小心設置,過長的曝光時間也有可能引起光電陰極板的損壞。

            2. 曝光、觸發

            觸發模式分為:Single Trigger Mode, Multi Trigger Mode, Double Trigger Mode;

            a. single trigger mode

            image

            系統延時與脈沖延時是硬件上的延時是無法避免的,它們總共的時間在100ns以內,延時時間(Delay)(0-1000s)與曝光(Exposure)(x-1000s,x脈沖時序相關)時間是人為設定的。因為它是單觸發模式,每一次觸發都帶有系統與脈沖上的延遲。在每次循環之間也需要額外的時間。

            b. multi trigger mode

            image

            延遲時間0-999ms,曝光時間在20ns-999ms之間。

            c. double trigger mode

            image

            posted @ 2012-06-29 21:46 鐘謝偉 閱讀(1609) | 評論 (0)編輯 收藏

            簡易定時器設計

            需求:

                  要運用番茄時間管理,沒有像文中所說的定時器,用手機也怎么方便,因為本身就經常是在計算機前工作學習的。那么下一個軟件呢?有那么一款PomoTime,既包含了定時的功能,又含有添加Todolist,統計當天的番茄時間等的功能,而我僅僅需要一個定時功能,因為對于Todolist還是希望采用紙筆的方式進行記錄。原來嘗試看桌面右下角的時間,還判斷一個番茄時間是否結束,發現工作中,往往因為過于集中注意力或分散注意力瀏覽網頁去了而忘記對時間的查看,同時又想將自己所學的知識進行運用,于是想到了這么個方式,自己編寫一個簡易的定時器吧。

            功能描述:

            1. 顯示分,秒,處于桌面最前面;

            2. 設定分,秒;

            3. 當設定的時間消耗完后會彈出對話框,進行提醒;

            (這里沒有采用聲音提醒的原因是若采用這種方式,會影響到別人的辦公與學習。)

            語言選擇:

            由于這僅僅是一個很簡單的功能實現,對于語言沒有很大的要求,選擇了C++,庫為wxWidget。

            界面設計:

            使用wxFormBuilder

            關鍵點描述:

                在整個過程中遇到的問題的地方時,如何進行倒計時?最先想到的就是onTimer這樣類似的功能,在wxWidget庫中找到了具有該功能的wxTimer類,在手冊中這么一句話 its precision is platform-dependent, but in general will not be better than 1ms nor worse than 1s. 也就是說采用該方法進行時間設定可能每一次都會造成1ms-1s時間上的誤差,這個誤差不是很大,對于整個的設計目的并沒有太大的影響。

                全部源碼在Simple timer source code

                關于時間處理的部分代碼如下:

               1: // timer_app.h
               2: ////////////////////////////////////////////////////////////////////////////////
               3: // main application frame declaration
               4: ////////////////////////////////////////////////////////////////////////////////
               5:  
               6: class TimerFrame : public MainDialogBase
               7: {
               8: public:
               9:     TimerFrame( wxWindow *parent );
              10:     virtual ~TimerFrame();
              11:  
              12: protected:
              13:     // protected event handlers
              14:     virtual void OnCloseDialog( wxCloseEvent& event );
              15:     virtual void OnSetButtonClick( wxCommandEvent& event );
              16:     virtual void OnStartButtonClick( wxCommandEvent& event );
              17:     
              18: public:
              19:     void OnTimer( wxTimerEvent& event );
              20:     
              21: private:
              22:     int m_minute;
              23:     int m_second;
              24:     wxTimer *m_clock;
              25:     wxDECLARE_EVENT_TABLE();    
              26: };
              27:  
              28: // timer_app.cpp
              29: // event list, combine timer event with OnTimer function
              30: wxBEGIN_EVENT_TABLE(TimerFrame, MainDialogBase)
              31: EVT_TIMER(TIMER_ID, TimerFrame::OnTimer)
              32: wxEND_EVENT_TABLE()
              33:  
              34: //......some code......
              35:  
              36: TimerFrame::TimerFrame(wxWindow *parent) : MainDialogBase( parent )
              37: {
              38:     m_clock = new wxTimer();               // create a new wxTimer
              39:     m_clock->SetOwner(this, TIMER_ID);     // set owner, #define TIMER_ID 1000
              40:     m_minute = 25;
              41:     m_second = 0;
              42: }
              43:  
              44: //......some code......
              45:  
              46: // count down the time and show
              47: void TimerFrame::OnTimer(wxTimerEvent& event)
              48: {
              49:     // determine the minute and second wait to show
              50:     if (m_second == 0 && m_minute == 0) {
              51:         m_clock->Stop();
              52:         wxMessageBox(wxT("Time over"),wxT("Timer"));
              53:         return;
              54:     } else if (m_second ==0) {
              55:         m_second = 59;
              56:         m_minute -= 1;
              57:     } else {
              58:         m_second -= 1;
              59:     }
              60:     wxString sTmp;
              61:     sTmp.Printf(wxT("%d"),m_minute);
              62:     m_minuteTextCtrl->SetValue(sTmp);
              63:     sTmp.Printf(wxT("%d"),m_second);
              64:     m_secondTextCtrl->SetValue(sTmp);
              65: }
              66:  

            posted @ 2012-06-28 15:35 鐘謝偉 閱讀(1442) | 評論 (3)編輯 收藏

            僅列出標題
            共4頁: 1 2 3 4 
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導航

            統計

            常用鏈接

            留言簿(1)

            隨筆檔案

            IT網站

            My Friends

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            国产精品免费久久久久久久久 | 国产亚洲精午夜久久久久久| 国产精品久久久久久一区二区三区| 国产精品久久久久无码av| 久久久久久久亚洲精品| 人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 97久久超碰成人精品网站| 久久综合色老色| 久久夜色精品国产噜噜亚洲AV| 国产亚洲精久久久久久无码| 国产精品成人无码久久久久久| 久久亚洲AV无码精品色午夜麻豆 | 久久99精品综合国产首页| 久久夜色撩人精品国产| 久久国产精品久久久| 漂亮人妻被中出中文字幕久久| 丰满少妇人妻久久久久久4| 性欧美大战久久久久久久久| 一本一道久久a久久精品综合| 91亚洲国产成人久久精品| 无码人妻久久一区二区三区免费丨 | 久久人人爽人人爽人人片AV麻豆 | 久久久久久久91精品免费观看| 久久精品国产半推半就| 麻豆久久| 久久精品国产色蜜蜜麻豆| 国内高清久久久久久| 国产一区二区精品久久凹凸| 国产99久久精品一区二区| 2021国产精品午夜久久| 久久综合成人网| 久久久久亚洲AV无码去区首| 国产69精品久久久久99| 丰满少妇人妻久久久久久4| 99久久精品九九亚洲精品| 99久久亚洲综合精品成人| avtt天堂网久久精品| 丁香狠狠色婷婷久久综合| 久久夜色tv网站| 久久久WWW成人免费精品| 久久午夜无码鲁丝片午夜精品|