ArduCAMで撮った画像をFTPサーバに送る

# ArduCAM to FTP
## 0. Motivation
ArduinoのカメラモジュールArduCAM-Mini-2MPで撮った、連続した2画像の差分が大きい場合のみ、その画像をサーバ上にコピーしたかったのすが、ググっても撮った画像をSDカード(モジュール)上に保存するサンプルしか見つかりませんでした。

## 1. ArduCAMでjpgフォーマットとして画像を撮る
下記にArduCAM-Mini-2MPでjpg画像として撮って、Arduionoのバッファ上に保持するサンプルはありました。
https://github.com/Dasch0/esp32-arducam-edge-impulse/blob/main/src/main.cpp

## 2. jpg画像をデコードして２枚の画像の差分を取る
下記Tiny JPEG Decompressorはjpg画像をArduino内蔵メモリでもデコードできます。
http://elm-chan.org/fsw/tjpgd/en/appnote.html
これを使って、連続した2枚のjpg画像をデコードし、ピクセル毎に比較することにしました。

上記Exampleのstruct *IODEV*を、ファイルのポインタではなくArduCAMで撮ったjpg画像(char型の配列)のポインタをInput stream *\*jbuf*として渡せるように、そのサイズも*lbyte*として渡せるように修正してます。加えて、デコード時に、前回デコードされた画像とのピクセル間の差分の和を保持する*diff*というメンバも追加しています。
```
// TJpgDec Session identifier for input/output functions (name, members and usage are as user defined)
typedef struct {
    char *jbuf;             /* Input stream */
    uint8_t *fbuf;          /* Output frame buffer */
    unsigned int wfbuf;     /* Width of the frame buffer [pix] */
    uint32_t lbyte;         /* Number bytes left in the input stream */
    int diff;               /* difference between current and previous frame buffers */
} IODEV;
```
同様にinput functionを、ファイル操作でなく上記struct *IODEV*で渡されるjpg画像(*\*jbuf*)をmemcpyでread buffer *buff*に*nbyte*分コピーしするよう修正しています。
```
// TJpgDec User defined input function
size_t in_func (    /* Returns number of bytes read (zero on error) */
    JDEC* jd,       /* Decompression object */
    uint8_t* buff,  /* Pointer to the read buffer (null to remove data) */
    size_t nbyte    /* Number of bytes to read/remove */
)
{
    IODEV *dev = (IODEV*)jd->device;   /* Session identifier (5th argument of jd_prepare function) */

    /* Copy input stream, dev->jbuf, to read buffer, buff */
    if (nbyte > dev->lbyte)
      nbyte = dev->lbyte;
    if (buff) /* Read data from imput stream */
      memcpy(buff, dev->jbuf, nbyte);
    dev->lbyte -= nbyte;
    dev->jbuf += nbyte;

    return nbyte;
}
```
output functionは、入力jpg画像をデコードしたビットマップ画像bitmapを出力frame buffer *wfbuf*にコピーする際に、*wfbuf*に残っている前回のピクセル値とbitmapの同じピクセルの値の差分の二乗和平方根の和を上記struct *IODEV*のメンバ*diff*に保持します。
```
// TJpgDec User defined output function
unsigned int out_func (      /* Returns 1 to continue, 0 to abort */
    JDEC* jd,       /* Decompression object */
    void* bitmap,   /* Bitmap data to be output */
    JRECT* rect     /* Rectangular region of output image */
)
{
    IODEV *dev = (IODEV*)jd->device;   /* Session identifier (5th argument of jd_prepare function) */
    uint8_t *src, *dst;
    uint16_t y, bws, i;
    unsigned int bwd;

    /* Progress indicator */
    if (rect->left == 0) {
        if(Serial)
          Serial.printf("\r%lu%%. ", (rect->top << jd->scale) * 100UL / jd->height);
    }
    /* Copy the output image rectangle to the frame buffer */
    src = (uint8_t*)bitmap;                           /* Output bitmap */
    dst = dev->fbuf + N_BPP * (rect->top * dev->wfbuf + rect->left);  /* Left-top of rectangle in the frame buffer */
    bws = N_BPP * (rect->right - rect->left + 1);     /* Width of the rectangle [byte] */
    bwd = N_BPP * dev->wfbuf;                         /* Width of the frame buffer [byte] */
    for (y = rect->top; y <= rect->bottom; y++) {
      for (i = 0; i < bws/N_BPP; i++){  /* Calculate the difference between output bitmap and previous frame buffer before copy */
        dev->diff += sq((int)dst[i*3] - (int)src[i*3]);
        dev->diff += sq((int)dst[i*3 + 1] - (int)src[i*3 + 1]);
        dev->diff += sq((int)dst[i*3 + 2] - (int)src[i*3 + 2]);
      }
      memcpy(dst, src, bws);   /* Copy a line */
      src += bws; dst += bwd;  /* Next line */
    }

    return 1;    /* Continue to decompress */
}
```

## 3. jpg画像をFTPサーバに送る
下記で対象をFTPサーバにコピーできます。
https://playground.arduino.cc/Code/FTP/

上記で計算した連続した2枚のjpg画像の差分*diff*が、ある一定値(ここでは20000000)以上だと、FTPで新しい方の画像をftpサーバに保存してます。
```
  if (devid.diff > 20000000) { // ftp the current jpg image if the difference between current and previous and images is more than this value
    doFTP(jpeg_buffer, jpeg_size);
    ...
  }
```

## 4. まとめ
上記三つのサンプルを下記の通り組み合わせて、所望の(連続した2画像のうち差分の大きい)jpg画像をFTPサーバに送れました。
https://github.com/kamotsuru/arducam2ftp/blob/main/arducam2ftp.ino