

タイトルの通り、SpresenseでのRGB565フォーマットによる高解像度画像の取得についてご教示頂きたく。

Cameraのサンプルを使用してRGB565フォーマットでVGAやFULL
HD画質での画像取得を実施しようとしておりますが、エラーが出て取得することが出来ません。  
RGB565でもQVGAでの取得や、JPGフォーマットでの高解像度画像の取得は問題なく出来ております。  
RGB565 QVGAでの取得サイズが150KBなので、VGA程度なら600KBで取得出来そうですがそれも出来ません。

Spresenseのメモリ領域が小さいことが起因していそうですが、対策等分かればご教示頂けませんでしょうか？

### 試したこと

  * Spresenseのメモリサイズを1536KBに変更 ← 効果なし
  * Streaming関数の停止 ← 効果なし

### エラー内容

  * RGB565 VGAサイズ  
`>>Error: Invalid parameter`

  * RGB565 FULL HDサイズ  
`>>Error: No memory`

### 変更しているコード部分

[code]

      theCamera.setStillPictureImageFormat(
         CAM_IMGSIZE_VGA_H,
         CAM_IMGSIZE_VGA_V,
         CAM_IMAGE_PIX_FMT_RGB565);
    
[/code]

以上、宜しくお願いします。


CC BY-SA 4.0
2022-02-27T11:07:43.497
86599
2022-03-11T15:55:54.043
2022-02-28T01:21:34.800
3060
51626
question
spresense arduino camera
SpresenseでのRGB565フォーマットによる高解像度画像の取得ができない


自分も以前、気になってこの件調べてみました。

spresense-nuttx/arch/arm/src/cxd56xx/cxd56_cisif.c

の59行目の

[code]

    #define YUV_VSIZE_MAX  (360)
    #define YUV_HSIZE_MAX  (480)
    
[/code]

と、749行目の

[code]

    static int cisif_chk_yuvfrmsize(int w, int h)
    {
      if ((w < YUV_HSIZE_MIN) || (w > YUV_HSIZE_MAX))
        {
          return -EINVAL;
        }
    
      if ((h < YUV_VSIZE_MIN) || (h > YUV_VSIZE_MAX))
        {
          return -EINVAL;
        }
    
      return OK;
    }
    
    
[/code]

で、360x480 以下として、判定をしています。

このことから、360x480 以下という仕様なのだと思われます。


CC BY-SA 4.0
2022-02-28T17:10:39.307
86620
2022-02-28T17:10:39.307
32281
86599
answer


トリッキーな技ですが JPEG で取り込んで、RGB に展開してファイルに出力するということができます。Arduino で行う場合は、Spresense
Arduino Board Package に **libjpeg** を取り込む必要があります。

やり方を[ここ](https://ja.stackoverflow.com/questions/73301/spresense-
arduino-%e3%81%a7-libjpeg-%e3%82%92%e4%bd%bf%e3%81%84%e3%81%9f%e3%81%84)に紹介していますが、ボードパッケージを作るのは面倒だと思うので、独自パッケージを
Github リポジトリに公開しました。必要でしたら使ってみてください。README に従って、Arduino IDE に URL
を設定すれば、ボードマネージャーからインストールできます。

<https://github.com/YoshinoTaro/spresense-arduino-libjpeg>

さて、肝心のやり方ですが、上記のリポジトリにもサンプルがありますが、簡略化したコードを掲載しておきます。JPEG を展開した
RGBデータをファイルに保存できます。（メモリ展開も試してみたのですが、かなり大きな画像なのでメモリ不足で無理でした）

この技を拡張すれば、指定した ROI のみを部分デコードして RGB に展開することもできます。この場合、ROI
が小さければメモリにも展開できます。上記リポジトリ内にサンプルがありますので、もしよろしければ参照してみてください。

[code]

    /* [注意！]
     * このコードを試すには、libjpeg が有効になった Spresense Arduino
    *  Board Package が必要です。次のURLで取得できます。(V2.4.0 base)
     * (Spresense libjpeg Boards: Spresense libjpeg)
     * https://github.com/YoshinoTaro/spresense-arduino-libjpeg
     */
    #include <Camera.h>
    #define HAVE_BOOLEAN
    
    #include <nuttx/config.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <libjpeg/jpeglib.h>
    #include <string.h>
    extern "C" {
    #include <setjmp.h>
    }
    
    const int width  = CAM_IMGSIZE_VGA_H;
    const int height = CAM_IMGSIZE_VGA_V;
    const char filename[10] = "out.rgb";
    
    extern "C" bool decode_jpeg_to_file(uint8_t* imgbuf, uint32_t imgsize
      , const char* filename);
    
    void setup() {  
      Serial.begin(115200);
      theCamera.begin();
      theCamera.setStillPictureImageFormat(
        width, height, CAM_IMAGE_PIX_FMT_JPG);
      CamImage img = theCamera.takePicture();
      if (!img.isAvailable()) {
        Serial.println("Cannot take a picture");
        return;
      }
    
      if (!decode_jpeg_to_file(img.getImgBuff(), img.getImgSize()
                     , filename)) {
        Serial.println("decode error");
        return;
      }
    
      Serial.println("the decoded image saved as out.rgb");
      Serial.println("Please change the filename to out.data to visualize by GIMP");
    
      // end the camera to reset the format and free the image buffer
      theCamera.end(); 
    }
    
    void loop() {}
    
    bool decode_jpeg_to_file(uint8_t* imgbuf, uint32_t imgsize
         , const char* filename) {
          
      struct stat buf;
      for (;;) {
        sleep(1);
        int ret = stat("/mnt/sd0", &buf);
        if (ret) printf("Please insert formateed SD Card.\n");
        else break;
      }
      
      char path[20] = "/mnt/sd0/";
      strcat(path, filename);
      printf("Filie path: %s\n", path);
      FILE* out = fopen(path, "wb");
      if (out == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        return false;
      }
      printf("create %s\n", filename);
      
      static struct jpeg_decompress_struct cinfo;
      struct jpeg_error_mgr jerr;  
    
      cinfo.err = jpeg_std_error(&jerr);
      jpeg_create_decompress(&cinfo);
    
      jpeg_mem_src(&cinfo, imgbuf, imgsize);
    
      jpeg_read_header(&cinfo, TRUE);
    
      cinfo.out_color_space = JCS_RGB;
    
      jpeg_start_decompress(&cinfo);
      printf("cinfo.output_width:  %d\n", cinfo.output_width);  
      printf("cinfo.output_height: %d\n", cinfo.output_height);  
    
      JSAMPARRAY buffer; /* Output row buffer */
      int row_stride;    /* physical row width in output buffer */
      row_stride = cinfo.output_width * 3; // in case of RGB
      buffer = (*cinfo.mem->alloc_sarray)
                    ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
    
      printf("Step6: read scanlines\n");
      int n = 0;  /* for debug */
      while (cinfo.output_scanline < height) {
        jpeg_read_scanlines(&cinfo, buffer, 1);
        if (row_stride != fwrite(buffer[0], 1, row_stride, out)) {
          printf("fwrite error : %d\n", errno);
        }
        ++n;
      }
      printf("read lines: %d\n", n); /* for debug */
      fclose(out);
    
      jpeg_finish_decompress(&cinfo);
      jpeg_destroy_decompress(&cinfo);
      return true;
    }
    
[/code]


CC BY-SA 4.0
2022-03-11T15:42:45.550
86802
2022-03-11T15:55:54.043
2022-03-11T15:55:54.043
27334
27334
86599
answer