Resources for this article :
[1] (Strongly Recommend!) Fundamentals and Experiments of Line Scan Camera:
[2] Linear array CCD How to use ( With TCD1304 For example ):

Project address :

Original address :



This is a continuation 【 Hard core photography 】 Take a full body picture of the train and Application of optical flow method —— Adaptive detection of video train speed The content of . But in fact, the relationship between the whole project and the previous work is not so close , It can only be regarded as a spiritual sequel .

actually , This article 2.0 The content of is the spiritual ancestor of video scanning code at the software level . The original project of this scanning camera [1] yes 2011 It was designed around 2000 , Lao pan is about 2018 See this in and try to reproduce ( Failure ), But I've been thinking about this project . Because I have a general understanding of the principle , So I made a simulation version of this camera with video recording . It turns out that 2021 I suddenly learned that , At home PCB The manufacturer actually started proofing for free , So Lao pan decided to restart the project , Bid farewell to the complicated flying line , Disassemble the original hole plate , Go straight up PCB.

Lao pan made some small changes on the basis of the original design . This article is mainly to record the countless pits in the process of reproduction , And some guidelines for the improvement of this project .

This project is completely open source in github On , Including circuit ,PCB, Hardware code , Various materials, etc .

Lao pan is not specialized in hardware development , So there must be many places that don't understand , I hope you can give guidance or correct .

Some effects show :

This is a still life sweeping across the table , Because the hands shake, there will be deformation .

This is a roadside camera , Because the aperture is at its maximum , Focus on the center lane , Close range will be out of focus and blurred .

A complete scan result , The original image without adjusting the length width ratio .

The train arrived late but , Unfortunately, it's very difficult for this camera to get accurate view and focus , Resulting in low film yield .

linear vs A two-dimensional

The principle that this one-dimensional camera can also take pictures has been introduced in the previous chapter , If you understand the principle of linear scanning , The principle of this camera as like as two peas . Just use linear CCD Shoot directly from ( Or record a video ) This place is already in a fixed position - Continuous framing - The process of stitching pictures frame by frame .

At this time, someone will ask : Since you can use a video recorder to record directly, then use a software puzzle , There is no need to use linear CCD To do this ? At this time, we should consider the advantages and disadvantages of the two methods , To choose which method to use .

  • linear CCD The resolution of the device can be easily achieved 10000×n, namely CCD The single frame coverage pixels can be very high , This is difficult to achieve on the current two-dimensional sensor ( Even better than GFX 100 You can do the longest side 11648×8736 The resolution of the , But the cost explosion , And it brings a second problem )
  • linear CCD Only 1 Dimension data , In high-speed acquisition, the requirements for peripheral circuits are lower (GFX 100 And a linear CCD, At the same time 1000 Frame sampling speed , The difference in difficulty is obvious ). Someone will say : The sampling rate limitation of two-dimensional devices can be compensated by two-dimensional plane ( namely ,11648×8736×1 frame , The image acquisition range is equivalent to 11648×1×8736 frame ), But the previous experiments have proved that , The premise of using the narrow window of video to simulate linear scanning is , The size of the window should not be too large , Otherwise, there will be a perspective effect . therefore , A two-dimensional CMOS perhaps CCD Devices will waste a lot of data .
  • Continue the previous article , Using linearity CCD It can save storage space and IO expenses .
  • Use CCD The disadvantage of , Due to the upper limit of sampling rate , Therefore, objects whose speed exceeds the upper limit of the frame rate will deform , And the lost frame details cannot be made up , Through the video recording and post-processing of two-dimensional devices , Narrow windows can be used to make up .( The speed here - Frame rate - The window size relationship was also derived in the previous work , linear CCD Set the window width to fixed 1 that will do )
  • For all that , Narrow windows still cause the following problems , And it is difficult to correct it by simple later techniques :
  1. The window width is closely related to the target motion speed , And divided into positive and negative .
  2. An object with perspective , Unable to unify the window width .
  3. For variable speed objects , Very sensitive to window width .
  4. When an object is reflected by light and shadow at a fixed position, it will produce fringe interference .

As shown in the figure :

The above problem is that the window width is equal to 1 Pixels , That is, the linear CCD When capturing an image , These defects can be eliminated . For example, as shown in the figure below , The car photographed belongs to a two-way Lane , The big truck blocked by the white line runs from right to left , The car in front of the white line runs from left to right . But because the pixel width of each frame is 1, Therefore, the frame arrangement order will not have the problem shown in the figure above 1 The effect of , It will only affect whether the mirror image of the object is flipped or not ( Pay attention to the words on the truck ).

As for the tensile deformation of the object , Can pass ps Zoom simple correction . Objects with slow motion and elongated image can be pressed back to normal size , No loss of information ; And the image shortening caused by too fast motion , Using only interpolated Faraday back to the original scale will bring information loss .

Introduction to sensors

The basic principle

The most important part of the whole project is the sensor , What we use here is TCD32D Linear monochrome sensor , have 1024 Pixel units , The maximum capture speed can reach about... Per second 2000 frame . In fact, the current technology has up to 10000 pixels , Higher resolution can be achieved , And support RGB Color mode , But the principles of these things are basically the same . to want to TCD132D Output something , First, you need to give it some signals , As shown in the figure :

here SH Is to control the CCD Collect optical signals , Control the accumulation of electrical signals converted from light intensity ( That's integral ) The length of time taken , Meet a SH The falling edge makes CCD Start to carry the accumulated electrical signals out . So you can see that , The higher the frame rate , The shorter the integration time for each pixel , Equivalent to lower sensitivity . At the same time ,\phiϕCCD Control the rhythm of handling , This signal changes once , Let the signal of the next pixel come out , Until all the pixels are gone . But not all the pixels above can capture the optical signal , Only the middle part 1024 One can , Others can only make soy sauce .\phiϕM It's the total clock , According to the scale in the picture, you can see ,\phiϕCCD Change once , It's going to correspond to \phiϕM change 4 Time , That is to say \phiϕM The frequency needs to be \phiϕCCD Of 4 times .

The frequency range of these signals that the sensor can accept is shown in the first three rows of the table below . You can see \phiϕM The frequency of is indeed \phiϕCCD Of 4 times . and \phiϕCCD Each change will output a data , That is, a \phiϕCCD The cycle will have 2 Data output , So the data rate is \phiϕCCD Twice as many . One frame has 1024 Data , Per second 2M Data per second 2k A frame , So the speed of this sensor is... Per second 2 About a thousand frames .

This TCD132D The output is an analog signal ( The voltage value of a continuous interval ), So you need a ADC To convert the voltage value to 0-255 Digital values between . That means , We need one that can support conversion per second 2M Data ADC Talent .ADC1173 You can achieve 15MHz. And the way to drive him is simple , Use a clock , The current data acquisition will be converted every time the falling edge of the clock .

Lao pan used... Earlier arduino Try to drive TCD132D as well as ADC1173, But there is no oscilloscope , It is impossible to check whether the output signal meets the expected value ,arduino mega It doesn't have DMC, There's no time to capture the data in turn . And how to synchronize data between columns , I don't have a clue . Here's a demonstration of using arduino+ADC1173 Come and put this CCD As an example of the use of light sensors ( but ).

Fortunately mega There are many timers that can be used , These timers are used by me as clocks . Configuring the timer involves register operation , My humble opinion is that registers are a bunch of function buttons , Pressing it will produce the corresponding function , These functions are arranged and combined to form a magical or strange running posture ... The way to use the corresponding register is by setting the name of a variable ( Generally used MCU will make the corresponding file of name and bottom address of each register for everyone ) Equal to a binary number , Each bit of this binary number corresponds to a button in this register ,1 Just press ,0 Just don't press . Switch these buttons back and forth through a variety of fascinating eyes , The machine runs .

But in general , It may not be appropriate to directly set a register equal to a number . Because sometimes we just want to change one of several buttons , Don't want to move other buttons , If you manually set the state of a large row of buttons every time , It's easy to get wrong . So sometimes you can use logical symbols to specify the operation of a button .

//  Give Way DDRB Of the 0 Position and number 1 A into 1  here | It's bitwise OR 
DDRB |= (00000001 | 00000010);

//  Give Way ADCSRA Of ADPS0:2 become 0  there & It's bitwise and 
ADCSRA &= ~((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0));

// Arduino Inside _BV() The use of is equivalent to setting a bit to 1 DDRB and DDB7 Already predefined 


therefore arduino The clock settings for each part , Combine the instructions in the manual with the routines on the Internet , You can write the following :

void setup() {
    // read one frame (line)
    // Init the port to output mode
    DDRB |= _BV(DDB7) | _BV(DDB5) | _BV(DDB4);
    DDRE |= _BV(DDE3);
    DDRH |= _BV(DDH3);

    // LEDCLK (pin 13)(PB7)
    TCCR0A = _BV(COM0A1) | _BV(WGM01) | _BV(WGM00);
    TCCR0B = _BV(CS00);
    OCR0A = 255;

    // MCLK (pin 11)(PB5)
    TCCR1A = _BV(COM1A0);
    TCCR1B = _BV(WGM12) | _BV(CS10);
    OCR1A = 1;             // 4MHz
    PORTB |= _BV(PORTB5);  // start from HIGH

    // CCD (pin 10)(PB4)
    TCCR2A = _BV(COM2A0) | _BV(WGM21);
    TCCR2B = _BV(CS20);
    OCR2A = 7;  // 1MHz

    // ADCCLK (pin 5)(PE3)
    TCCR3A = _BV(COM3A0);
    TCCR3B = _BV(WGM32) | _BV(CS30);
    OCR3A = 3;  // 2MHz
    TCNT3 = 3;

    // SH (pin 6)(PH3) total: 1092x500ns = 546us
    TCCR4A = _BV(COM4A1) | _BV(WGM41);
    TCCR4B = _BV(WGM42) | _BV(WGM43) | _BV(CS40);
    OCR4A = 7;
    ICR4 = 8735;
    TCNT4 = 18;


The wiring is as follows ( Too lazy to draw a detailed picture of the bread board , Just take a look at the picture )

The sequence diagram is as follows , do not know why ADC The clock is always out of alignment , But as long as ADC The falling edge is CCD Near the change , In this range CCD The output signal is still stable .( To be verified by oscilloscope )

Finally through Arduino collection ADC Output value , We can see a certain response law . In the experiment, it is found that the sensor outputs low potential when the light is bright , Output high potential when there is no light , And the situation in general digital images is just the opposite .

In addition, it also wrote a word with Arduino Boring code for making breathing lights , It's on the board 13 The lamp that comes with the port . But this breathing lamp uses a timer , And the law of change is sinusoidal ( It still feels useless ).

void led_blink() {
  for (float i = 0; i < 5000; i++) {
    int t = 255 * 0.5 * (1 + sin(i / 5000 * 2 * PI));
    OCR0A = t;


CCD Aging

If you capture an image in a very dark environment , Then highlight the picture by adjusting the curve or color scale , It's possible to see this stripe . According to the reference link [2], This phenomenon is because CCD It is caused by the small error of the two amplifiers inside the sensor .

in fact , Most linear arrays CCD In order to increase the output frequency , Have multiple Shift Register The design of the structure , At this point, the difference between theory and practice can be used to explain the linear array CCD At the end of life , Often the signal will appear strange periodicity ( False signal ) The phenomenon of . for instance TCD1304 There are two sets Shift Register, So after a long time of use , Two Shift Register The aging condition of the corresponding analog amplifier is inconsistent , Therefore, in the output signal , The signal of each even pixel is always higher than that of adjacent odd pixels , Or always lower )

Linear camera implementation details

This section describes the various pits that may be encountered during copying in order , So as not to copy your homework well .

Say at the front , It doesn't matter whether the components here use patches or connectors .( For my own convenience , Can use direct plug-ins are used , The actual test didn't find much problem )

Replace the display with SSD1306 module

Various components used by the original author , At that time, I could basically collect , And it doesn't cost too much . Only what he used OLED The display is completely missing . So this part simply uses the price of Taobao cabbage OLED Module is OK . After some research , It's used here 4 Linear SPI and OLED signal communication , So buy that 7 A pin OLED modular . thus , The power supply part of the display screen in the original design can also be removed , Because there is power supply management on the module . But that's not enough , Because the original OLED Driver chips are different from those common on Taobao , So change the code .

Fortunately, the store gave SSD1306 Routine for , And the changes are relatively simple , Just change the initialization parameters . In the original disp.c Inside 233 OK, here's the thing :

static const BYTE ini[] = {    /* Initialization parameters for UG-2832ASWAG or UG-2864ASWAG */
        0xDB, 0x3F,        /* Vcom level */
        0xD9, 0x1F,        /* Pre/Dis-charge period */
        0xA1,            /* Column direction (L/R inverted) */
        0xC8,            /* COM direction (U/D inverted) */
        0xDA, 0x12,        /* COM scan alt mode */
        0xA8, 0x3F,        /* Mux ratio (2832:1F, 2864:3F) */
        0xD5, 0xF0,        /* Clock */
        0x81, 0x64,        /* Contrast (2832:0x14, 2864:0x64) */
        0xD3, 0x00,        /* Display offset (0) */
        0xAD, 0x8A,        /* Internal DC-DC (off) */
        0xA6,            /* Display invert mode (normal) */
        0xA4,            /* Entire display (0) */
        0x40            /* Display start line (0) */


If you change the initialization parameter here to SSD1306 Of , And follow the wiring mode in the circuit diagram I modified , Plug in the module directly and you can use it normally :

static const BYTE ini[] = {    /* Initialization parameters for SSD1306 */
        0xAE,//--turn off oled panel
        0x00,//--set low column address
        0x10,//--set high column address
        0x40,//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
        0x81,//--set contrast control register
        0xCF,//--Set SEG Output Current Brightness
        0xA1,//--Set SEG/Column Mapping      0xa0: horizonal reverse  0xa1: none
        0xC8,//--Set COM/Row Scan Direction  0xc0: vertical reverse   0xc8: none
        0xA6,//--set normal display
        0xA8,//--set multiplex ratio(1 to 64)
        0x3f,//--1/64 duty
        0xD3,//--set display offset    Shift Mapping RAM Counter (0x00~0x3F)
        0x00,//--not offset
        0xd5,//--set display clock divide ratio/oscillator frequency
        0x80,//--set divide ratio, Set Clock as 100 Frames/Sec
        0xD9,//--set pre-charge period
        0xF1,//--Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
        0xDA,//--set com pins hardware configuration
        0xDB,//--set vcomh
        0x40,//--Set VCOM Deselect Level
        0x20,//--Set Page Addressing Mode (0x00/0x01/0x02)
        0x8D,//--set Charge Pump enable/disable
        0x14,//--set(0x10) disable
        0xA4,//--Disable Entire Display On (0xa4/0xa5)
        0xA6,//--Disable Inverse Display On (0xa6/a7) 
        0xAF //--turn on oled panel


But there are still some small problems , In this way, the screen can be displayed , But there are 2 Pixel offset . Pay attention to one in the upper left corner ], In fact, that is the rightmost box of the battery logo in the upper right corner . Although this is harmless , But I don't know how to fix this bug.

The code to compile

The author gave a Makefile file , Therefore, as long as the compilation environment is configured , Enter the source file path and execute directly make Command is enough . But one small detail is ,Linux The environment must be configured first arm-linux-eabi-gcc compiler ( You can use it directly sudo apt-get install gcc-arm-none-eabi, and apt-get install lsb-core) Can be smooth make. Finally, if the compilation is successful, a obj Folder , There will be a hex file , The terminal will display this .

hex Download it to the master

There's a big problem here , Originally, I couldn't connect to this single chip microcomputer , Once thought it was burning out the chip during welding ( What a coincidence. Unfortunately, I removed this chip from the original circuit , And it took a long time to install the chip on the new board ). As a result, I looked at the records I left many years ago , When downloading, you need to reset the chip and pull down a pin , Get into ISP The pattern is good . The specific operation is : take P2.10(ISP) Set low , At the same time let reset For low , Then let go RST, Let go ISP, To load BootLoader, Otherwise flash magic Can't recognize the chip (LOW on this pin while RESET is LOW forces on-chip bootloader to take over control of the part after a reset.). The way to judge is : Use flash magic, If you click ISP-Read Device Signature Be able to get out of the equipment ID, That is, success is connected .

For two pin operation , You need to manually plug these two pins into any GND On . At that time PCB I didn't pay attention to the operation of this part , Of course, you can also take the drawings , Add two buttons to this part by yourself . Downloader TX Mouth and RX The port should be connected to the... On the main control board RX and TX On the feet .

in addition , When downloading the program , Try to remove the other two boards , I found it in Control Board There are Analog Board When , Always fail to disconnect on the way to download the program . It may be the problem of insufficient power supply ?


The original author of this part only gave one abl file , Need to use ispLEVER classic Operate , But I already did it in those years , And get the binary file written directly into the device . This part of the code really touches my knowledge blind spot , I really can't change anything , So I didn't study it carefully . As for the download method , First use lattice Download line , After connecting the line, power on the main control board separately , The download line is not powered . Then use the software to operate . The compilation, download and other operations of the software part can be operated according to the manual . The instructions are also github Inside the .


Here, it is necessary to adjust the partial voltage of the rheostat to control the signal strength output by the sensor in the darkest environment , Or it can be understood as zero calibration . We expect the image value to be 0. Adjust the exposure if necessary , I hope to output pictures with a certain brightness in a very dark environment. You can also adjust them here . By changing the resistance of this rheostat , Cover the lens , Observe the brightness intensity on the screen to the desired position ( Under normal conditions , In the dark, the light curve on the screen is also in the center dotted line ). However, it should be noted that the gain at the algorithm level should be set to 0 Then adjust the rheostat .


It is necessary to insert a memory card when starting up , Otherwise, it will report a mistake . But if you insert a memory card, you still report an error , Check your memory card format , Need to be for FAT32 Can only be . Now the new memory cards are relatively large , It's usually exFAT Format and windows The system's own right-click format cannot be formatted as FAT32, It can be used DiskGenius format , Please check the data before formatting .

Maximum record length

stay lcam.h The first line of is the parameter to set the maximum record length , When any button of the camera is pressed , Or when the maximum record length is reached , Record stop . The original setting is 100000, But you can make it bigger . But pay attention to ,FAT32 The maximum file size supported by the system is 4GB. meanwhile ,BMP Format file header through bfSize Define file size ,bfSize Occupy 4 Bytes , Therefore, the maximum file storage supported is also 4GB.

BMP Image transfer PNG

When the image exceeds a certain size , With a normal photo viewer or even Photoshop May not be able to open the file properly , But use Windows You can view the self-contained drawing . Out-of-service PS The editor was furious , But since some software can see, some can't see , and PS There is no problem with pictures with large editing operation , So I guess it may be because BMP Coding problem . Because of this BMP The color table information inside is user-defined , Maybe PS The support for this is not very good .

So you can use the original data python Read into memory first , Then transfer it to a more general PNG Format , It can not only compress the volume, but also make PS edit . The code is very simple . Just a few lines in total , as follows . Too lazy to copy and paste github There are .

import cv2

image_path = 'Y0023.BMP'
image = cv2.imread(image_path)
cv2.imwrite('{}_modified.png'.format(image_path[:-4]), image)


Light path and lens

First, make sure that the image field of the lens can cover CCD The length of . Secondly, the distance from the outer plane of the fuselage flange to the sensor should be designed according to the flange distance corresponding to the bayonet of the lens used . Here is a hand drawn dimension of the soul , For reference only .

I directly got a carton for the fuselage to install the circuit and card lens , But the fuselage needs to be sealed without light leakage , If there is a leak in the box ( Especially close to the sensor ) You'd better make up . About how to get the flange , You can remove the flange by collecting waste cameras at a low price , Or buy the cheapest bayonet adapter ring to get it . However, when picking the adapter ring, pay attention to the difference between male and female of the flange .

Image tearing problem

If you use older / Less known and inferior brand / Cheap memory card , You will find that the following situations often occur ,

The fault at the rear of the car shows that the data here is Caton , The collected data is not saved in time, resulting in frame loss . Lao pan used a memory card with a rather slow write speed , It happens all the time . Used a newly bought U1 Speed memory card , This happens occasionally . Use one U3 Memory card , This rarely happens .

Camera operation method

In the original author's blog . There is no need to copy and paste again here .

Black and white photography experience

Lao pan also learned some experiences about black-and-white photography . Many people say that photography is the art of using light , Especially in black-and-white photography , No color blessings , Light is very important . For example, the train here , Because it is backlight, the whole backlight area appears very flat , No texture , The edges of the car body don't feel at all . But the cloth on the roof receives good light , The ups and downs are obvious , Light and shadow change very much .