Skip to content

Portenta Vision Shield, bitmap to SD Card update sketch #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,126 +1,144 @@
#include "SDMMCBlockDevice.h" // Multi Media Card APIs
#include "FATFileSystem.h" // Mbed API for portable and embedded systems
#include "FATFileSystem.h" // API to run operations on a FAT file system
SDMMCBlockDevice blockDevice;
mbed::FATFileSystem fileSystem("fs");

#include "camera.h" // Arduino Mbed Core Camera APIs
#include "himax.h" // Exclusive Camera library for the Portenta Vision Shield
#include "himax.h" // API to read from the Himax camera found on the Portenta Vision Shield
HM01B0 himax;
Camera cam(himax);

FrameBuffer fb; // Buffer to save the capture
FrameBuffer frameBuffer; // Buffer to save the camera stream

// Settings for our setup
#define RES_H (unsigned int)240
#define RES_W (unsigned int)320
#define IMAGE_HEIGHT (unsigned int)240
#define IMAGE_WIDTH (unsigned int)320
#define IMAGE_MODE CAMERA_GRAYSCALE
#define IMAGE_BPP (unsigned int)8
#define BITS_PER_PIXEL (unsigned int)8
#define PALETTE_COLORS_AMOUNT (unsigned int)(pow(2, BITS_PER_PIXEL))
#define PALETTE_SIZE (unsigned int)(PALETTE_COLORS_AMOUNT * 4) // 4 bytes = 32bit per color (3 bytes RGB and 1 byte 0x00)
#define IMAGE_PATH "/fs/image.bmp"

// Headers info
#define HEADER_FILE_HEADER (unsigned int)14
#define HEADER_DIB_SIZE (unsigned int)40
#define HEADER_FULL_SIZE (HEADER_FILE_HEADER + HEADER_DIB_SIZE)
#define PALETTE_SIZE (2 ^ IMAGE_BPP) * 4 // 4 bytes per color
#define BITMAP_FILE_HEADER_SIZE (unsigned int)14 // For storing general information about the bitmap image file
#define DIB_HEADER_SIZE (unsigned int)40 // For storing information about the image and define the pixel format
#define HEADER_SIZE (BITMAP_FILE_HEADER_SIZE + DIB_HEADER_SIZE)

void setup()
{
Serial.begin(115200);
while (!Serial)
;

// Mount SD Card
mountSD();
void setup(){
Serial.begin(115200);
while (!Serial && millis() < 5000);

Serial.println("Mounting SD Card...");
mountSDCard();
Serial.println("SD Card mounted.");

// Init the cam QVGA, 30FPS, Grayscale
if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 30))
{
if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 30)){
Serial.println("Unable to find the camera");
}

// Save the headers and the image data into the .bmp file
parseData();
countDownBlink();
Serial.println("Fetching camera image...");
unsigned char *imageData = captureImage();
digitalWrite(LEDB, HIGH);

Serial.println("Saving image to SD card...");
saveImage(imageData, IMAGE_PATH);

fileSystem.unmount();
Serial.println("Done. You can now remove the SD card.");
}

void loop()
{
while (1)
;
void loop(){
}

// Mount File system block
void mountSD()
{
Serial.println("Mounting SD Card...");

void mountSDCard(){
int error = fileSystem.mount(&blockDevice);
if (error)
{
Serial.println("No SD Card found");
while (1)
;
if (error){
Serial.println("Trying to reformat...");
int formattingError = fileSystem.reformat(&blockDevice);
if (formattingError) {
Serial.println("No SD Card found");
while (1);
}
}
}

void parseData()
{
unsigned char *imgData = NULL;
int fileSize = HEADER_FILE_HEADER + RES_W * RES_H;

FILE *file = fopen("/fs/image.bmp", "w+");

// Get a Frame
if (cam.grabFrame(fb, 3000) == 0)
{
// Save the raw image data (8bpp grayscale)
imgData = fb.getBuffer();
}
else
{
// Get the raw image data (8bpp grayscale)
unsigned char * captureImage(){
if (cam.grabFrame(frameBuffer, 3000) == 0){
return frameBuffer.getBuffer();
} else {
Serial.println("could not grab the frame");
while (1)
;
while (1);
}
// Bitmap structure (Head + DIB Head + ColorMap + binary image)
unsigned char bitmapFileHeader[HEADER_FILE_HEADER];
unsigned char bitmapDIBHeader[HEADER_DIB_SIZE];
unsigned char colorMap[PALETTE_SIZE]; // Needed for <=8bpp grayscale bitmaps
}

// Set the file headers to 0
memset(bitmapFileHeader, (unsigned char)(0), HEADER_FILE_HEADER);
memset(bitmapDIBHeader, (unsigned char)(0), HEADER_DIB_SIZE);
memset(colorMap, (unsigned char)(0), PALETTE_SIZE);
// Set the headers data
void setFileHeaders(unsigned char *bitmapFileHeader, unsigned char *bitmapDIBHeader, int fileSize){
// Set the headers to 0
memset(bitmapFileHeader, (unsigned char)(0), BITMAP_FILE_HEADER_SIZE);
memset(bitmapDIBHeader, (unsigned char)(0), DIB_HEADER_SIZE);

// Write the headers info
// File header
bitmapFileHeader[0] = 'B';
bitmapFileHeader[1] = 'M';
bitmapFileHeader[2] = (unsigned char)(fileSize);
bitmapFileHeader[3] = (unsigned char)(fileSize >> 8);
bitmapFileHeader[4] = (unsigned char)(fileSize >> 16);
bitmapFileHeader[5] = (unsigned char)(fileSize >> 24);
bitmapFileHeader[10] = (unsigned char)HEADER_FULL_SIZE + PALETTE_SIZE;
bitmapFileHeader[10] = (unsigned char)HEADER_SIZE + PALETTE_SIZE;

// Info header
bitmapDIBHeader[0] = (unsigned char)(HEADER_DIB_SIZE);
bitmapDIBHeader[4] = (unsigned char)(RES_W);
bitmapDIBHeader[5] = (unsigned char)(RES_W >> 8);
bitmapDIBHeader[8] = (unsigned char)(RES_H);
bitmapDIBHeader[8] = (unsigned char)(RES_H >> 8);
bitmapDIBHeader[14] = (unsigned char)(IMAGE_BPP);

// Color palette for grayscale Bitmaps (8bpp)
for (int i = 0; i < (2 ^ IMAGE_BPP); i++)
{
bitmapDIBHeader[0] = (unsigned char)(DIB_HEADER_SIZE);
bitmapDIBHeader[4] = (unsigned char)(IMAGE_WIDTH);
bitmapDIBHeader[5] = (unsigned char)(IMAGE_WIDTH >> 8);
bitmapDIBHeader[8] = (unsigned char)(IMAGE_HEIGHT);
bitmapDIBHeader[9] = (unsigned char)(IMAGE_HEIGHT >> 8);
bitmapDIBHeader[14] = (unsigned char)(BITS_PER_PIXEL);
}

void setColorMap(unsigned char *colorMap){
//Init the palette with zeroes
memset(colorMap, (unsigned char)(0), PALETTE_SIZE);

// Gray scale color palette, 4 bytes per color (R, G, B, 0x00)
for (int i = 0; i < PALETTE_COLORS_AMOUNT; i++) {
colorMap[i * 4] = i;
colorMap[i * 4 + 1] = i;
colorMap[i * 4 + 2] = i;
}
}

// Save the headers and the image data into the .bmp file
void saveImage(unsigned char *imageData, const char* imagePath){
int fileSize = BITMAP_FILE_HEADER_SIZE + DIB_HEADER_SIZE + IMAGE_WIDTH * IMAGE_HEIGHT;
FILE *file = fopen(imagePath, "w");

// Write theh bitmap file
fwrite(bitmapFileHeader, 1, HEADER_FILE_HEADER, file);
fwrite(bitmapDIBHeader, 1, HEADER_DIB_SIZE, file);
fwrite(colorMap, 1, PALETTE_SIZE, file); // Color map
fwrite(imgData, 1, RES_H * RES_W, file);
// Bitmap structure (Head + DIB Head + ColorMap + binary image)
unsigned char bitmapFileHeader[BITMAP_FILE_HEADER_SIZE];
unsigned char bitmapDIBHeader[DIB_HEADER_SIZE];
unsigned char colorMap[PALETTE_SIZE]; // Needed for <= 8bpp grayscale bitmaps

setFileHeaders(bitmapFileHeader, bitmapDIBHeader, fileSize);
setColorMap(colorMap);

// Write the bitmap file
fwrite(bitmapFileHeader, 1, BITMAP_FILE_HEADER_SIZE, file);
fwrite(bitmapDIBHeader, 1, DIB_HEADER_SIZE, file);
fwrite(colorMap, 1, PALETTE_SIZE, file);
fwrite(imageData, 1, IMAGE_HEIGHT * IMAGE_WIDTH, file);

// Close the stream (bitmap file)
// Close the file stream
fclose(file);
}

void countDownBlink(){
for (int i = 0; i < 6; i++){
digitalWrite(LEDG, i % 2);
delay(500);
}
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, LOW);
}
6 changes: 3 additions & 3 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name=Arduino_Pro_Tutorials
version=1.0.5
version=1.0.6
author=Martino Facchin, Riccardo Ricco, Dario Pennisi, Sebastian Romero, Lenard George, Ignacio Herrera, Jose García, Pablo Marquínez
maintainer=Arduino <[email protected]>
sentence=This library contains the complete Arduino sketches from the Pro Tutorials.
paragraph=Instructions on how to use these sketches can be found on the Arduino Pro website under Documentation->Tutorials.
category=Other
url=https://www.arduino.cc/pro/tutorials/portenta-h7
architectures=mbed,mbed_portenta
url=https://docs.arduino.cc/#pro-family
architectures=mbed,mbed_portenta,mbed_nicla,mbed_edge
precompiled=false
depends=lvgl