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; }
}
};
}
}