1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #if defined(ARDUINO) && !defined(ARDUINO_SFE_EDGE)
17 #define ARDUINO_EXCLUDE_CODE
18 #endif  // defined(ARDUINO) && !defined(ARDUINO_SFE_EDGE)
19 
20 #ifndef ARDUINO_EXCLUDE_CODE
21 
22 #include "HM01B0.h"
23 #include "am_bsp.h"         //NOLINT
24 #include "am_mcu_apollo.h"  //NOLINT
25 #include "platform.h"       // TARGET specific implementation
26 
27 // Image is down-sampled by applying a stride of 2 pixels in both the x and y
28 // directions.
29 static const int kStrideShift = 1;
30 
31 //*****************************************************************************
32 //
33 //! @brief Read one frame of data from HM01B0 scaled to 96x96 RGB.
34 //!
35 //! @param buffer       - Pointer to the frame buffer.
36 //! @param w            - Image width.
37 //! @param h            - Image height.
38 //! @param channels     - Number of channels per pixel.
39 //!
40 //! This function reads data of one frame from HM01B0. It trims the image to an
41 //! even power of two mulitple of the requested width and height.  It down
42 //! samples the original image and duplicates the greyscale value for each color
43 //! channel.
44 //!
45 //! @return Error code.
46 //
47 //*****************************************************************************
hm01b0_blocking_read_oneframe_scaled(hm01b0_cfg_t * psCfg,int8_t * buffer,int w,int h,int channels)48 uint32_t hm01b0_blocking_read_oneframe_scaled(hm01b0_cfg_t* psCfg,
49                                               int8_t* buffer, int w, int h,
50                                               int channels) {
51   hm01b0_single_frame_capture(psCfg);
52 
53   // Calculate the number of pixels to crop to get a centered image.
54   const int offset_x = (HM01B0_PIXEL_X_NUM - (w * (1 << kStrideShift))) / 2;
55   const int offset_y = (HM01B0_PIXEL_Y_NUM - (h * (1 << kStrideShift))) / 2;
56 
57   uint32_t hsync_count = 0;
58 
59   while ((hsync_count < HM01B0_PIXEL_Y_NUM)) {
60     // Wait for horizontal sync.
61     while (!read_hsync())
62       ;
63 
64     // Get resulting image position.  When hsync_count < offset_y, this will
65     // underflow resulting in an index out of bounds which we check later,
66     // avoiding an unnecessary conditional.
67     const uint32_t output_y = (hsync_count - offset_y) >> kStrideShift;
68     uint32_t rowidx = 0;
69 
70     // Read one row. Hsync is held high for the duration of a row read.
71     while (read_hsync()) {
72       // Wait for pixel value to be ready.
73       while (!read_pclk())
74         ;
75 
76       // Read 8-bit value from camera.
77       const uint8_t value = read_byte();
78       const uint32_t output_x = (rowidx++ - offset_x) >> kStrideShift;
79       if (output_x < w && output_y < h) {
80         const int output_idx = (output_y * w + output_x) * channels;
81         for (int i = 0; i < channels; i++) {
82           // See the top of main_functions.cc for an explanation of and
83           // rationale for our unsigned to signed input conversion.
84           buffer[output_idx + i] = value - 128;
85         }
86       }
87 
88       // Wait for next pixel clock.
89       while (read_pclk())
90         ;
91     }
92 
93     hsync_count++;
94   }
95   return HM01B0_ERR_OK;
96 }
97 
98 #endif  // ARDUINO_EXCLUDE_CODE
99