C++ opencv实现raw格式图片的解析、缩放、旋转、调整亮度和对比度

···

include <stdlib.h>

include <time.h>

include <Windows.h>

include <iostream>

include <fstream>

include <thread>

include <opencv2/opencv.hpp>

include <opencv2/core/utils/logger.hpp>

using namespace std;
using namespace cv;

namespace opencv
{
namespace image
{

// read file content to buffer
char* file_read_all(string path, int& size)
{
  std::ifstream fin(path, std::ios::binary); if (!fin) { std::cerr << "open failed: " << path << std::endl; }
  fin.seekg(0, fin.end); size = fin.tellg(); fin.seekg(0, fin.beg); std::cout << "file size: " << size << std::endl;
  char* buf = new char[size]; fin.read(buf, size); return buf;     
}



class ImageProcessor
{
public:
  string path; // image file path
  int size=-1; // file size

  char* buf=0; // file content buffer
  int bytes_per_pixel = -1;  // buf中每个像素点的字节数
  int type = -1;             // buf中图片的格式,比如16UC1

  Mat img;     // 原始图片
  int w=-1;    // 原始图片的宽
  int h=-1;    // 原始图片的高
  int pixel_count = 0;        // 原始图片的像素个数
  uint8_t pixel_average = 0;  // 原始图片的像素平均值

  Mat resizedImg;              // 从原始图片resize后得到的图片,其像素值保持原始值不变
  int w_now = -1;              // resizedImg的宽
  int h_now = -1;              // resizedImg的高
  int pixel_count_now = 0;     // resizedImg的像素点个数

  Mat rotatedImg;              // 从resizedImg旋转后得到的图片,其像素值保持原始值不变
  double rotate_angle=0.0f;    // 旋转角度

  Mat nowImg;                  // 当前图片,以rotatedImg为基础,改变像素值得到,其像素值随时可以改变
  uint8_t pixel_average_now = 0;   // nowImg的像素平均值
  float bright_now = 1.0f;         // nowImg的亮度相对于原始图片亮度的比率
  float contrast_now = 1.0f;       // nowImg的对比度相对于原始图片的比率


  const uint8_t BestBright = 200;  // 最佳亮度,将nowImg的像素平均值调到这个值,即为最佳亮度
  const float U16Const = 255.0f / 65535.0f;
  const float BrightConst = 255.0f / 20000.0f;
  const float BrightConst2 =  20000.0f / 255.0f;
  const float ContrastConst = 0.9f / 10000.0f;
  const float ContrastConst1 = 9.0f / 10000.0f;
  const float ContrastConst2 = 10000.0f / 0.9f;
  const float ContrastConst3 = 10000.0f / 9.0f;

    ImageProcessor() { }
  ImageProcessor(string path) : path(path) {  }
  ~ImageProcessor() { if (buf) delete[] buf; }


  // 解析raw图片文件
  void parse_raw()
  {
    pixel_count = w * h; img = Mat::zeros(cv::Size(w, h), CV_8UC1);
    buf = file_read_all(path, size); if (size <= 0) { printf("file size error: %d\n", size); return; } if (buf == 0) { printf("file content error\n"); return; }
    bytes_per_pixel = size / pixel_count; printf("bytes for each pixel is %d\n", bytes_per_pixel);
    type = -1; if (bytes_per_pixel == 2) { type = CV_16UC1; } else if (bytes_per_pixel == 3) type = CV_8UC3; else if (bytes_per_pixel == 4) type = CV_8UC4; else if (bytes_per_pixel == 1) type = CV_8UC1;
    if (type != CV_16UC1) { printf("unknown type for %d bytes per pixel.\n", bytes_per_pixel); delete[] buf; buf = 0; return; }

    w_now = w; h_now = h; 
    fresh_raw();
  }

  void init_raw()
  {
        pixel_count = w * h; img = Mat::zeros(cv::Size(w, h), CV_8UC1);
    buf = (char*)(new uint16_t[pixel_count]);

    w_now = w; h_now = h; 
  }

  void fresh_raw(bool reset=false)
  {

    //LARGE_INTEGER t1, t2, tc; QueryPerformanceFrequency(&tc); QueryPerformanceCounter(&t1);

    if (reset) { w_now = w; h_now = h; rotate_angle = 0.0f; bright_now = 1.0f; contrast_now = 1.0f; }
    Mat img16 = Mat(cv::Size(w, h), type, buf);  auto data = (uint8_t*)img.data; auto data16 = (uint16_t*)img16.data;
    for (int i = 0; i < pixel_count; i++) { *data = (uint8_t)(*data16 * U16Const); data++; data16++; }

    pixel_average = get_pixel_average(img, pixel_count);
    resize(w_now, h_now);

    //QueryPerformanceCounter(&t2); auto time = (double)(t2.QuadPart - t1.QuadPart) / (double)tc.QuadPart; cout << "time = " << time << " seconds" << endl;
  }

  // 调整图片大小
  void resize(int w, int h)
  {
    if (w == this->w && h == this->h) img.copyTo(resizedImg); else cv::resize(img, resizedImg, Size(w, h), 0, 0, INTER_AREA);
    w_now = resizedImg.cols; h_now = resizedImg.rows; pixel_count_now = w_now * h_now;
    rotate(rotate_angle); 
  }
  // rate是相对于原始图片大小的比率
  void resize(float rate)
  {
    resize(w*rate, h*rate);
  }

  // 旋转
  void rotate(double angle)
  {
    rotate_angle = angle;
    if (angle == 0) { resizedImg.copyTo(rotatedImg); } 
    else
    { 
      Point2f center((w_now - 1) / 2.0, (h_now - 1) / 2.0); 
      Mat rotation_matix = getRotationMatrix2D(center, angle, 1.0); 
      warpAffine(resizedImg, rotatedImg, rotation_matix, Size(w_now, h_now));
    }
    rotatedImg.copyTo(nowImg); set_brightness_contrast(bright_now, contrast_now);
  }



  // 将亮度设置为原始图片的bright倍, 对比度设为原始图片的contrast倍
  void set_brightness_contrast(float bright, float contrast)
  {
    float diff = bright - contrast;
    auto buf_now = (uint8_t*)nowImg.data; auto buf2 = (uint8_t*)rotatedImg.data; float nowf;
    for (int i = 0; i < pixel_count_now; i++)
    {
      nowf = *buf2 * contrast + pixel_average*diff;  *buf_now = saturate_cast<uint8_t>(nowf); buf_now++; buf2++;
    }
    bright_now = bright; contrast_now = contrast;
  }
  // bright和contrast的取值范围均为0-20000
  void set_brightness_contrast(int bright, int contrast)
  {
    set_brightness_contrast(get_brightf(bright), get_contrastf(contrast));
  }
  // 将当前图片的亮度和对比度调到最佳
  void set_brightness_and_contrast_to_best()
  {
    float bright = 1.0f * BestBright / pixel_average; float contrast = (bright > 1.0f ? bright : 1.0f / bright);
    set_brightness_contrast(bright, contrast);
  }


  // 获取图片的像素平均值, pc为像素点个数
  uint8_t get_pixel_average(Mat& mat, int pc)
  {
    uint64_t sum = 0; auto buf2 = (uint8_t*)mat.data;
    for (int i = 0; i < pc; i++)
    {
      sum += *(buf2++);
    }
    uint8_t pixel_average = sum / (uint64_t)pixel_count; // printf("pixel average is %u\n", pixel_average);
    return pixel_average;
  }


  // 当前亮度值,范围0-20000
  int bright() { return bright_now * pixel_average * BrightConst2; }
  // 当前对比度,范围0-20000
  int contrast()
  {
    if (contrast_now <= 1.0f) return (contrast_now - 0.1) * ContrastConst2; else return (contrast_now - 1) * ContrastConst3 + 10000.0f;
  }
  // 将0-20000的亮度值转为对原始图片亮度值的比率
  float get_brightf(int bright)
  {
    return bright * BrightConst / pixel_average;
  }
  // 将0-20000的对比度转为对原始图片对比度的比率
  float get_contrastf(int contrast)
  {
    float contrast_f;   int contrast2 = contrast - 10000;
    if (contrast2 == 0) return 1.0f;
    else if (contrast2 > 0) return contrast2 * ContrastConst1 + 1.0f;
    else { return 0.1 + contrast * ContrastConst; }
  }



};

}
}

···

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容