AndroidのCamera写真補間アルゴリズム


一、rgb補間アルゴリズム
説明:検証が可能で、アルゴリズムの効率が一般的です.pDestは拡フレーム後のメモリアドレスであり、nDestWidthとnDestHeightは拡フレーム後の解像度であり、nDestBitsは色深度である(rgb 24のような).
void  rgbInterpolation(void* pDest, int nDestWidth, int nDestHeight, int nDestBits, void* pSrc, int nSrcWidth, int nSrcHeight, int nSrcBits)
{
 //ASSERT_EXP(pDest != NULL);
 //ASSERT_EXP((nDestBits == 32) || (nDestBits == 24));
 //ASSERT_EXP((nDestWidth > 0) && (nDestHeight > 0));
 
 //ASSERT_EXP(pSrc != NULL);
 //ASSERT_EXP((nSrcBits == 32) || (nSrcBits == 24));
 //ASSERT_EXP((nSrcWidth > 0) && (nSrcHeight > 0));
 
 double dfAmplificationX = ((double)nDestWidth)/nSrcWidth;
 double dfAmplificationY = ((double)nDestHeight)/nSrcHeight;
 
 const int nSrcColorLen = nSrcBits/8;
 const int nDestColorLen = nDestBits/8;
 
 for(int i = 0; i 0.5)
    ++nLine;
   
   if(nLine >= nSrcHeight)
    --nLine;
   
   tmp = j/dfAmplificationX;
   int nRow = (int)tmp;
   
   if(tmp - nRow > 0.5)
    ++nRow; 
   
   if(nRow >= nSrcWidth)
    --nRow;   
   
   unsigned char *pSrcPos = (unsigned char*)pSrc + (nLine*nSrcWidth + nRow)*nSrcColorLen;
   unsigned char *pDestPos = (unsigned char*)pDest + (i*nDestWidth + j)*nDestColorLen;
   
   *pDestPos++ = *pSrcPos++;
   *pDestPos++ = *pSrcPos++;
   *pDestPos++ = *pSrcPos++;
   
   if(nDestColorLen == 4)
    *pDestPos = 0;
  }
}
二、yuyv回転rgb、jpeg符号化のためのフレーム挿入アルゴリズム
説明:このアルゴリズムは検証されても良いです.効率は上よりやや高く、rgbの転化を省略し、さらにjpeg符号に組み込む.
/* private member functions */
/*
struct params {
  uint8_t* src;
  int src_size;
  uint8_t* dst; //     , buffer   3264*2448*3Byte
  int dst_size; //     ,   3264*2448*3Byte
  int quality;
  int in_width;
  int in_height;
  int out_width; //     ,   3264
  int out_height; //     ,   2448
  const char* format;
  size_t jpeg_size;
};
*/
size_t Encoder_libjpeg::encode(params* input) {
    jpeg_compress_struct    cinfo;
    jpeg_error_mgr jerr;
    jpeg_destination_mgr jdest;
    uint8_t* src = NULL, *resize_src = NULL;
    uint8_t* row_tmp = NULL;
    uint8_t* row_src = NULL;
    uint8_t* row_uv = NULL; // used only for NV12
    int row_stride;
    int out_width = 0, in_width = 0;
    int out_height = 0, in_height = 0;
    int bpp = 2; // for uyvy
    Encoder_libjpeg::format informat = Encoder_libjpeg::YUV422I;

    if (!input) {
        return 0;
    }

    out_width = input->out_width;
    in_width = input->in_width;
    out_height = input->out_height;
    in_height = input->in_height;
    src = input->src;
    input->jpeg_size = 0;

    libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size);

    // param check...
    if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) ||
         (src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) ||
         (input->dst_size < 1) || (input->format == NULL)) {
        goto exit;
    }

    if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
        //add by tankai
        if(in_width < out_height){ 
          informat = Encoder_libjpeg::RGB24;
        }
        else{
        //end tankai
        informat = Encoder_libjpeg::YUV420SP;
        bpp = 1;
        if ((in_width != out_width) || (in_height != out_height)) {
            resize_src = (uint8_t*) malloc(input->dst_size);
            resize_nv12(input, resize_src);
            if (resize_src) src = resize_src;
        }
        }//add by  tankai
    } else if (strcmp(input->format, CameraProperties::PIXEL_FORMAT_RGB24) == 0) {
        informat = Encoder_libjpeg::RGB24;
        bpp = 1;
        if ((in_width != out_width) || (in_height != out_height)) {
            resize_src = (uint8_t*) malloc(input->dst_size);
            if(NULL != resize_src){
                extraSmallImg(input->src, in_width, in_height,
                             resize_src, out_width, out_height);
                src = resize_src;
            }else{
                CAMHAL_LOGDA("failed to malloc space to extra thumbnail
"); goto exit; } } } else if ((in_width != out_width) || (in_height != out_height)) { CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %s", input->format); goto exit; } else if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)) { // we currently only support yuv422i and yuv420sp CAMHAL_LOGEB("Encoder: format not supported: %s", input->format); goto exit; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); CAMHAL_LOGDB("encoding...
\t" "width: %d
\t" "height:%d
\t" "dest %p
\t" "dest size:%d
\t" "mSrc %p", out_width, out_height, input->dst, input->dst_size, src); cinfo.dest = &dest_mgr; cinfo.image_width = out_width; cinfo.image_height = out_height; cinfo.input_components = 3; if (informat == Encoder_libjpeg::RGB24) cinfo.in_color_space = JCS_RGB; else cinfo.in_color_space = JCS_YCbCr; cinfo.input_gamma = 1; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, input->quality, TRUE); cinfo.dct_method = JDCT_IFAST; jpeg_start_compress(&cinfo, TRUE); row_tmp = (uint8_t*)malloc(out_width * 3); row_src = src; row_uv = src + out_width * out_height * bpp; row_stride = out_width * 3; //add by tankai if(in_width < out_height){ int i,j,z,ratex,ratey=0; unsigned char *ptr; while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) { JSAMPROW row_pointer[1]; if ((ratey-=10)<0){ ratey+=51; ratex=0; ptr=row_tmp; z = 0; for (j=0; j<3264; j++){ if ((ratex-=10)<0){ ratex+=51; { int r, g, b; int y, u, v; if (!z) y = src[0] << 8; else y = src[2] << 8; u = src[1] - 128; v = src[3] - 128; r = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; b = (y + (454 * u)) >> 8; *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); if (z++){ z = 0; src += 4; } } }else{ register unsigned char rgbchar; rgbchar=*(ptr-3); *(ptr++)=rgbchar; rgbchar=*(ptr-3); *(ptr++)=rgbchar; rgbchar=*(ptr-3); *(ptr++)=rgbchar; } } } row_pointer[0] = row_tmp; jpeg_write_scanlines (&cinfo, row_pointer, 1); } } else //end tankai while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) { JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */ if (informat == Encoder_libjpeg::RGB24) { row[0] = &src[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row, 1); } else { // convert input yuv format to yuv444 if (informat == Encoder_libjpeg::YUV420SP) { nv21_to_yuv(row_tmp, row_src, row_uv, out_width); } else if (informat == Encoder_libjpeg::YUV422I) { //uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width); yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width); } row[0] = row_tmp; jpeg_write_scanlines(&cinfo, row, 1); row_src = row_src + out_width*bpp; // move uv row if input format needs it if (informat == Encoder_libjpeg::YUV420SP) { if (!(cinfo.next_scanline % 2)) row_uv = row_uv + out_width * bpp; } } } // no need to finish encoding routine if we are prematurely stopping // we will end up crashing in dest_mgr since data is incomplete if (!mCancelEncoding) jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); if (resize_src) free(resize_src); if (row_tmp) free(row_tmp); exit: input->jpeg_size = dest_mgr.jpegsize; return dest_mgr.jpegsize; }