Camera display on (ILI9341) TFT screen almost working

I am so close to getting this working but I cannot quite see how to fix this sorting algorithm.

As the attached picture shows, the image displayed is mirrored and the aspect ratio is wrong.

Here is the code.

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#include "camera.h"
#include "ov767x.h"

// Using a OV7675 cam

OV7675 ov767x;

Camera cam(ov767x);

// This define colour mode CAMERA_RGB565 (otherwise use CAMERA_GRAYSCALE for greyscale)
#define IMAGE_MODE CAMERA_RGB565

// For the TFT Display using SPI interface
#define TFT_RST     8
#define TFT_DC      9
#define TFT_CS      10
#define TFT_MOSI    11
#define TFT_CLK     13

/*
  Other buffer instantiation options:
  FrameBuffer fb(0x30000000);
  FrameBuffer fb(320,240,2);
*/
FrameBuffer fb(320,240,2);        // this defines a buffer to handle colour images - width, height & bits per pixel (change last parameter to 1 for greyscale)

unsigned long lastUpdate = 0;


// Using a breakout, change pins as desired
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, 12);


void blinkLED(uint32_t count = 0xFFFFFFFF)
{
  pinMode(LED_BUILTIN, OUTPUT);
  while (count--) {
    digitalWrite(LED_BUILTIN, LOW);  // turn the LED on (HIGH is the voltage level)
    delay(50);                       // wait for a second
    digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW
    delay(50);                       // wait for a second
  }
}


void setup() {
  // put your setup code here, to run once:

  Serial.begin(230400);
  while(!Serial) continue;
  Serial.println("Camera display on TFT demo!"); 
 
  tft.begin();
  
  // Init the cam QVGA, using 15fps instead of 30fps to get better refresh rate
  if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 15)) {
    blinkLED();
  }
  
  blinkLED(5);

  tft.fillScreen(ILI9341_BLACK);
  yield();
  tft.fillScreen(ILI9341_RED);
  yield();
  tft.fillScreen(ILI9341_GREEN);
  yield();
  tft.fillScreen(ILI9341_BLUE);
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();


}

void loop() {

  lastUpdate = millis();
  
  // Grab frame and write to serial
  if (cam.grabFrame(fb, 3000) == 0) {
    static FrameBuffer outfb(0x30000000);
    for (int i = 0; i < 320; i++) {
      for (int j = 0; j < 240; j++) {
        ((uint16_t*)outfb.getBuffer())[j + i * 240] = ((uint16_t*)fb.getBuffer())[i + j * 320];
        uint8_t lo_hi[] = { (uint8_t)((uint16_t*)outfb.getBuffer())[j + i * 240], (uint8_t)(((uint16_t*)outfb.getBuffer())[j + i * 240] >> 8) };
        ((uint16_t*)outfb.getBuffer())[j + i * 240] = (lo_hi[0] << 8) + lo_hi[1];
      }
    }
    tft.drawRGBBitmap(0,0,(uint16_t*)outfb.getBuffer(), 240, 320);
    //delay(2000);
  } else {
    blinkLED(20);
  }

 }

If anyone can help, that'll be most appreciated.

Thanks.

Hello,
Not sure what you mean by aspect wrong, the pic you show is 500 pixels tall by 374 pixels wide which is .748 aspect. From what I can find on your camera it's a 0.3MP: OV7675 · active array size: 640×480. This is an aspect also of .75.
Your code is defining 320x240 which is likewise a .75 aspect.
As to the mirroring, in the void loop, your second for loop needs to be reversed I think count wise.
Not sure on code, but instead of 0 to 240, go 240 to 0.

for (int j = 240; j > 0; j++) {

You picked the right loop to fix the mirroring but your suggestion did not work. Instead I kept the for loop as is i.e. for (int j = 0; j < 240; j++) { ... }

and then changed this line:

((uint16_t*)outfb.getBuffer())[j + (i * 240)] = ((uint16_t*)fb.getBuffer())[239 - i + j * 320];

This fixed the mirror but unfortunately, this introduced a new error... I get a split screen.

Regarding the aspect ratio... you can see by the shape of the pushbutton... it's elongated (or squashed), so does not match actual shape.

I need to rotate the image but still fill the 240 x 320 screen correctly.

I solved the split screen issue as well. I should have subtracted 319 and not 239...

((uint16_t*)outfb.getBuffer())[j + (i * 240)] = ((uint16_t*)fb.getBuffer())[319 - i + j * 320];

Now I just have to fix the aspect ratio or use the correct rotation with correct screen fill.

Is it the TFT doing the reverting or the camera?

There is another example available in the Arduino IDE, called "CameraCaptureRawBytes". This works fine, so I'm assuming that it is TFT related as the camera code is the same.