您当前的位置:首页 > 计算机 > 编程开发 > VC/VC++

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

时间:12-20来源:作者:点击数:

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
      int bits = 16;

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

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

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

      Mat nowImg;                  // 当前图片,以rotatedImg为基础,改变像素值得到,其像素值随时可以改变
      int w_now = -1;              // rotatedImg的宽
      int h_now = -1;              // rotatedImg的高
      float bright_now = 1.0f;         // nowImg的亮度相对于原始图片亮度的比率
      float contrast_now = 1.0f;       // nowImg的对比度相对于原始图片的比率


      const uint8_t BestBright = 200;  // 最佳亮度,将nowImg的像素平均值调到这个值,即为最佳亮度
      float U16Const;
      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(int bits = 16): bits(bits) { U16Const = 255.0f / (pow(2, bits) - 1); }
      ImageProcessor(string path, int bits=16) : path(path),  bits(bits)  { U16Const = 255.0f / (pow(2, bits) - 1); }
      ~ImageProcessor() { if (buf) delete[] buf; }


      // 解析raw, type==-1时由程序自动检测type值,否则使用指定的type值
      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; if(bytes_per_pixel* pixel_count!=size) { printf("file size %d is not multiple times of pixel count %d.\n", size, pixel_count); delete[] buf; buf = 0; return; }
        printf("bytes for each pixel is %d\n", bytes_per_pixel);

        if (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 && type != CV_16SC1) { printf("unknown type for %d bytes per pixel.\n", bytes_per_pixel); delete[] buf; buf = 0; return; }

        w_resize = w; h_resize = 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_resize = w; h_resize = h;
      }

      void fresh_raw(bool reset=false)
      {

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

        if (reset) { w_resize = w; h_resize = 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;
        if (type == CV_16UC1) { for (int i = 0; i < pixel_count; i++) { *data = (uint8_t)(*data16 * U16Const); data++; data16++; } }
        else if (type == CV_16SC1) { for (int i = 0; i < pixel_count; i++) { *data = (uint8_t)(((int)(*(int16_t*)data16) + 32768) * U16Const);  data++; data16++; } }
       

        pixel_average = get_pixel_average(img, pixel_count);
        resize(w_resize, h_resize);

        //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_resize = resizedImg.cols; h_resize = resizedImg.rows; pixel_count_resize = w_resize * h_resize;
        rotate(rotate_angle); 
      }
      // rate是相对于原始图片大小的比率
      void resize(float rate)
      {
        resize(w*rate, h*rate);
      }

      // 旋转, mode=1时自动扩展图片尺寸以包含全部图片信息,mode=0时保持原来的图片尺寸,部分图片信息会在旋转后丢失
      void rotate(double angle, int mode=1)
      {
        rotate_angle = angle;
        if (angle == 0.0) { w_rotate = w_resize; h_rotate = h_resize; resizedImg.copyTo(rotatedImg); }
        else
        { 
          if (mode == 0)
          {
            cv::Point2f center((w_resize - 1) / 2.0, (h_resize - 1) / 2.0);
            cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
            w_rotate = w_resize; h_rotate = h_resize;
            cv::warpAffine(resizedImg, rotatedImg, rot, Size(w_rotate, h_rotate));
          }
          else 
          {
            double alpha = -angle * CV_PI / 180.0;
            cv::Point2f srcP[3], dstP[3];
            srcP[0] = cv::Point2f(0, h_resize); srcP[1] = cv::Point2f(w_resize, 0); srcP[2] = cv::Point2f(w_resize, h_resize);
            for (int i = 0; i < 3; i++) dstP[i] = cv::Point2f(srcP[i].x * cos(alpha) - srcP[i].y * sin(alpha), srcP[i].y * cos(alpha) + srcP[i].x * sin(alpha));
            double minx, miny, maxx, maxy;
            minx = std::min(std::min(std::min(dstP[0].x, dstP[1].x), dstP[2].x), float(0.0));
            miny = std::min(std::min(std::min(dstP[0].y, dstP[1].y), dstP[2].y), float(0.0));
            maxx = std::max(std::max(std::max(dstP[0].x, dstP[1].x), dstP[2].x), float(0.0));
            maxy = std::max(std::max(std::max(dstP[0].y, dstP[1].y), dstP[2].y), float(0.0));
            w_rotate = maxx - minx; h_rotate = maxy - miny;
            for (int i = 0; i < 3; i++) { if (minx < 0) dstP[i].x -= minx; if (miny < 0) dstP[i].y -= miny; }
            cv::Mat warpMat = cv::getAffineTransform(srcP, dstP);
            cv::warpAffine(resizedImg, rotatedImg, warpMat, cv::Size(w_rotate, h_rotate));
          }
        }
        w_now = w_rotate; h_now = h_rotate;
        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_resize; 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; }
      }



    };

  }
}

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门