# 图像处理自动曝光算法

## 自动曝光修复算法附完整C代码

2018-06-02 21:42:00 jiubanbannixue 阅读数 2332
• ###### 数字成像系统

数字成像系统暨Image signal processor原理培训，涵盖成像系统基础5讲：1.... ISP 信号处理基础，以及ISP各模块：6.黑电平与线性化7.Green Imbalance8：9.坏点消除等21讲，3A技术以及图像质量评价与调校6讲

34课时 949分钟 9072人学习 姜卓
免费试看

AF自动对焦(Automatic Focus)

AE自动曝光(Automatic Exposure)

AW自动白平衡(Automatic White Balance)

matlab代码如下:

% Seperate the Channels

R=A(:,:,1);

G=A(:,:,2);

B=A(:,:,3);

% Calculate Intensity Component

I=(R+G+B)/3;

% Invert the image

I_inverted=255-I;

% Apply Average Filter to obtain the Mask Image

h_average=fspecial('average',15);

M=imfilter(I_inverted,h_average);

% Color Correction for R channel

R_new=zeros(size(R));

[c_y, c_x,~] = size(R);

for j = 1:c_x

for i = 1:c_y

p=double(R(i,j));

q=double(M(i,j));

R_new(i,j,:)=int8(255*((p/255)^(2^((128-q)/128))));

end

end

% Color Correction for G channel

G_new=zeros(size(G));

[c_y, c_x,~] = size(G);

for j = 1:c_x

for i = 1:c_y

p=double(G(i,j));

q=double(M(i,j));

G_new(i,j,:)=int8(255*((p/255)^(2^((128-q)/128))));

end

end

% Color Correction for B channel

B_new=zeros(size(B));

[c_y, c_x,~] = size(B);

for j = 1:c_x

for i = 1:c_y

p=double(B(i,j));

q=double(M(i,j));

B_new(i,j,:)=int8(255*((p/255)^(2^((128-q)/128))));

end

end

% Output Image

O=zeros(size(A));

O(:,:,1)=R_new;

O(:,:,2)=G_new;

O(:,:,3)=B_new;

% Convert the double output image to uint8

O=uint8(O);

% Plot the images

subplot(1,3,1), imshow(A), title('Original Image');

subplot(1,3,3), imshow(O), title('Output Image');

void LocalColorCorrection(unsigned char *Input, unsigned char *Output, int Width, int Height, int Channels) {

unsigned char *Mask = (unsigned char *) malloc(Width * Height * sizeof(unsigned char));

return;

unsigned char LocalLut[256 * 256];

unsigned char *pLocalLut = LocalLut + (mask << 8);

for (int pix = 0; pix < 256; ++pix) {

pLocalLut[pix] = ClampToByte(255.0f * powf(pix / 255.0f, powf(2.0f, (128.0f - mask) / 128.0f)));

}

}

InvertGrayscale(Input, Output, Width, Height, Channels);

int Radius = (MAX(Width, Height) / 512) + 1;

for (int Y = 0; Y < Height; Y++) {

unsigned char *pOutput = Output + (Y * Width * Channels);

unsigned char *pInput = Input + (Y * Width * Channels);

for (int X = 0; X < Width; X++) {

unsigned char *pLocalLut = LocalLut + (pMask[X] << 8);

for (int C = 0; C < Channels; C++) {

pOutput[C] = pLocalLut[pInput[C]];

}

pOutput += Channels;

pInput += Channels;

}

}

}

/**

*implmentation of Local Color Correction using Non-Linear Masking published by Nathan Moroney Hewlett-Packard Laboratories, Palo Alto, California.

**/

#include "browse.h"

#define USE_SHELL_OPEN

#define STB_IMAGE_STATIC

#define STB_IMAGE_IMPLEMENTATION

#include "stb_image.h"

/* ref:https://github.com/nothings/stb/blob/master/stb_image.h */

#define TJE_IMPLEMENTATION

#include "tiny_jpeg.h"

/* ref:https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h */

#include <math.h>

#include <stdbool.h>

#include <stdio.h>

#include "timing.h"

#include <stdint.h>

#include <assert.h>

#ifndef _MAX_DRIVE

#define _MAX_DRIVE 3

#endif

#ifndef _MAX_FNAME

#define _MAX_FNAME 256

#endif

#ifndef _MAX_EXT

#define _MAX_EXT 256

#endif

#ifndef _MAX_DIR

#define _MAX_DIR 256

#endif

#ifndef MIN

#define MIN(a, b) ( (a) > (b) ? (b) : (a) )

#endif

#ifndef MAX

#define MAX(a, b) (((a) > (b)) ? (a) : (b))

#endif

char saveFile[1024];

unsigned char *loadImage(const char *filename, int *Width, int *Height, int *Channels) {

return (stbi_load(filename, Width, Height, Channels, 0));

}

void saveImage(const char *filename, int Width, int Height, int Channels, unsigned char *Output) {

memcpy(saveFile + strlen(saveFile), filename, strlen(filename));

*(saveFile + strlen(saveFile) + 1) = 0;

if (!tje_encode_to_file(saveFile, Width, Height, Channels, true, Output)) {

fprintf(stderr, "save JPEG fail. ");

return;

}

#ifdef USE_SHELL_OPEN

browse(saveFile);

#endif

}

void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {

const char *end;

const char *p;

const char *s;

if (path[0] && path[1] == ':') {

if (drv) {

*drv++ = *path++;

*drv++ = *path++;

*drv = '';

}

} else if (drv)

*drv = '';

for (end = path; *end && *end != ':';)

end++;

for (p = end; p > path && *--p != '\' && *p != '/';)

if (*p == '.') {

end = p;

break;

}

if (ext)

for (s = end; (*ext = *s++);)

ext++;

for (p = end; p > path;)

if (*--p == '\' || *p == '/') {

p++;

break;

}

if (name) {

for (s = p; s < end;)

*name++ = *s++;

*name = '';

}

if (dir) {

for (s = path; s < p;)

*dir++ = *s++;

*dir = '';

}

}

void getCurrentFilePath(const char *filePath, char *saveFile) {

char drive[_MAX_DRIVE];

char dir[_MAX_DIR];

char fname[_MAX_FNAME];

char ext[_MAX_EXT];

splitpath(filePath, drive, dir, fname, ext);

size_t n = strlen(filePath);

memcpy(saveFile, filePath, n);

char *cur_saveFile = saveFile + (n - strlen(ext));

cur_saveFile[0] = '_';

cur_saveFile[1] = 0;

}

int GetMirrorPos(int Length, int Pos) {

if (Pos < 0)

return -Pos;

else if (Pos >= Length)

return Length + Length - Pos - 2;

else

return Pos;

}

unsigned char ClampToByte(int Value) {

if (Value < 0)

return 0;

else if (Value > 255)

return 255;

else

return (unsigned char) Value;

}

void FillLeftAndRight_Mirror(int *Array, int Length, int Radius) {

for (int X = 0; X < Radius; X++) {

Array[Radius + Length + X] = Array[Radius + Length - X - 2];

}

}

int SumOfArray(const int *Array, int Length) {

int Sum = 0;

for (int X = 0; X < Length; X++) {

Sum += Array[X];

}

return Sum;

}

void BoxBlurGrayscale(unsigned char *input, unsigned char *output, int Width, int Height, int Radius) {

if ((input == NULL) || (output == NULL)) return;

if ((Width <= 0) || (Height <= 0) || (Radius <= 0)) return;

int SampleAmount = (2 * Radius + 1) * (2 * Radius + 1);

float Inv = 1.0f / SampleAmount;

int *ColValue = (int *) malloc((Width + Radius + Radius) * sizeof(int));

int *ColOffset = (int *) malloc((Height + Radius + Radius) * sizeof(int));

if ((ColValue == NULL) || (ColOffset == NULL)) {

if (ColValue != NULL) free(ColValue);

if (ColOffset != NULL) free(ColOffset);

return;

}

for (int Y = 0; Y < Height + Radius + Radius; Y++)

ColOffset[Y] = GetMirrorPos(Height, Y - Radius);

{

for (int Y = 0; Y < Height; Y++) {

unsigned char *scanLineOut = output + Y * Width;

if (Y == 0) {

memset(ColValue + Radius, 0, Width * sizeof(int));

unsigned char *scanLineIn = input + ColOffset[Z + Radius] * Width;

for (int X = 0; X < Width; X++) {

}

}

} else {

unsigned char *RowMoveOut = input + ColOffset[Y - 1] * Width;

unsigned char *RowMoveIn = input + ColOffset[Y + Radius + Radius] * Width;

for (int X = 0; X < Width; X++) {

RowMoveOut[X] - RowMoveIn[X];

}

}

int LastSum = SumOfArray(ColValue, Radius * 2 + 1);

scanLineOut[0] = ClampToByte((int) (LastSum * Inv));

for (int X = 0 + 1; X < Width; X++) {

int NewSum = LastSum - ColValue[X - 1] + ColValue[X + Radius + Radius];

scanLineOut[X] = ClampToByte((int) (NewSum * Inv));

LastSum = NewSum;

}

}

}

free(ColValue);

free(ColOffset);

}

void InvertGrayscale(unsigned char *Input, unsigned char *Output, int Width, int Height, int Channels) {

if (Channels == 1) {

for (unsigned int Y = 0; Y < Height; Y++) {

unsigned char *pOutput = Output + (Y * Width);

unsigned char *pInput = Input + (Y * Width);

for (unsigned int X = 0; X < Width; X++) {

pOutput[X] = (unsigned char) (255 - pInput[X]);

}

}

} else {

for (unsigned int Y = 0; Y < Height; Y++) {

unsigned char *pOutput = Output + (Y * Width);

unsigned char *pInput = Input + (Y * Width * Channels);

for (unsigned int X = 0; X < Width; X++) {

pOutput[X] = (unsigned char) (255 - ClampToByte(

(21842 * pInput[0] + 21842 * pInput[1] + 21842 * pInput[2]) >> 16));

pInput += Channels;

}

}

}

}

void LocalColorCorrection(unsigned char *Input, unsigned char *Output, int Width, int Height, int Channels) {

unsigned char *Mask = (unsigned char *) malloc(Width * Height * sizeof(unsigned char));

return;

unsigned char LocalLut[256 * 256];

unsigned char *pLocalLut = LocalLut + (mask << 8);

for (int pix = 0; pix < 256; ++pix) {

pLocalLut[pix] = ClampToByte(255.0f * powf(pix / 255.0f, powf(2.0f, (128.0f - mask) / 128.0f)));

}

}

InvertGrayscale(Input, Output, Width, Height, Channels);

int Radius = (MAX(Width, Height) / 512) + 1;

for (int Y = 0; Y < Height; Y++) {

unsigned char *pOutput = Output + (Y * Width * Channels);

unsigned char *pInput = Input + (Y * Width * Channels);

for (int X = 0; X < Width; X++) {

unsigned char *pLocalLut = LocalLut + (pMask[X] << 8);

for (int C = 0; C < Channels; C++) {

pOutput[C] = pLocalLut[pInput[C]];

}

pOutput += Channels;

pInput += Channels;

}

}

}

int main(int argc, char **argv) {

printf("Local Color Correction demo ");

printf("blog:http://cpuimage.cnblogs.com/ ");

if (argc < 2) {

printf("usage: %s image ", argv[0]);

printf("eg: %s d:\image.jpg ", argv[0]);

return (0);

}

char *szfile = argv[1];

getCurrentFilePath(szfile, saveFile);

int Width = 0;

int Height = 0;

int Channels = 0;

unsigned char *inputImage = NULL;

double startTime = now();

inputImage = loadImage(szfile, &Width, &Height, &Channels);

if ((Channels != 0) && (Width != 0) && (Height != 0)) {

unsigned char *outputImg = (unsigned char *) stbi__malloc(Width * Channels * Height * sizeof(unsigned char));

if (inputImage) {

memcpy(outputImg, inputImage, (size_t) (Width * Channels * Height));

} else {

}

startTime = now();

LocalColorCorrection(inputImage, outputImg, Width, Height, Channels);

double nProcessTime = calcElapsed(startTime, now());

printf("process time: %d ms. ", (int) (nProcessTime * 1000));

startTime = now();

saveImage("done.jpg", Width, Height, Channels, outputImg);

double nSaveTime = calcElapsed(startTime, now());

printf("save time: %d ms. ", (int) (nSaveTime * 1000));

if (outputImg) {

stbi_image_free(outputImg);

}

if (inputImage) {

stbi_image_free(inputImage);

}

} else {

}

getchar();

printf("press any key to exit. ");

return (EXIT_SUCCESS);

}

## 图像处理的3A算法是什么

2019-11-03 13:28:21 hahahahhahha 阅读数 619
• ###### 数字成像系统

数字成像系统暨Image signal processor原理培训，涵盖成像系统基础5讲：1.... ISP 信号处理基础，以及ISP各模块：6.黑电平与线性化7.Green Imbalance8：9.坏点消除等21讲，3A技术以及图像质量评价与调校6讲

34课时 949分钟 9072人学习 姜卓
免费试看

3A技术即自动对焦（AF）、自动曝光（AE）和自动白平衡（AWB）。

3A数字成像技术利用了AF自动对焦算法、AE自动曝光算法及AWB自动白平衡算法来实现图像对比度最大、改善主体拍摄物过曝光或曝光不足情况、使画面在不同光线照射下的色差得到补偿，从而呈现较高画质的图像信息。

3A技术长久以来被认为是数字图像技术中最有挑战性的技术。

3A性能的好坏决定了拍摄画面的明亮度，色调接近抑或偏离自然并且也决定了聚焦速度快慢。特别在拍摄场景的照明条件和被拍摄物体经常变化的环境条件下获取高画质图像尤为重要。例如户外用安防摄像机等。

自动曝光

## 图像传感器与信号处理——自动曝光算法

2020-02-21 15:43:37 weixin_44580210 阅读数 339
• ###### 数字成像系统

数字成像系统暨Image signal processor原理培训，涵盖成像系统基础5讲：1.... ISP 信号处理基础，以及ISP各模块：6.黑电平与线性化7.Green Imbalance8：9.坏点消除等21讲，3A技术以及图像质量评价与调校6讲

34课时 949分钟 9072人学习 姜卓
免费试看

# 图像传感器与信号处理——自动曝光算法

## 2. 基于直方图统计的算法

（1）An Advanced Video Camera System with Robust AF, AE, and AWB Control，2001
（2）Real-time Image Fusion and Adaptive Exposure Control for Smart Surveillance Systems，2007
（3） 2.3 Automatic Camera Exposure Control，2007
（4） 2.4 Autonomous Configuration of Parameters in Robotic Digital Cameras，2009

### 2.1 Acquisition of Agronomic Images with Sufficient Quality by Automatic Exposure Time Control and Histogram Matching，2013

$\text{ while } \left(m_{i} \geq m_{u i} \text { and } \gamma_{i} \geq\left|\gamma_{u i}\right|\right) \text{or} \left(m_{i} \leq m_{l i} \text { and } \gamma_{i} \geq \gamma_{l i}\right)$$E T=\left(\frac{m_{R r e f}+m_{G r e f}}{m_{R}+m_{G}}\right) E T_{c u r r}$其中$m_{i}$$\gamma_{i}$为图像第$i$个通道的均值和偏度（红绿蓝三个通道，但是由于农用场景的限制，这篇文章只考虑红和绿两个通道），$m_{u i}$$m_{l i}$分别是均值的最大最小边界，$\gamma_{u i}$$\gamma_{l i}$分别是偏度的最大最小边界。$m_{R r e f}$$m_{G r e f}$分别为参考图像的直方图平均值，通过上式就可以计算出优化后的曝光时间，即ET modification中的过程。

## 4. 基于梯度的算法

### 4.1 Active Exposure Control for Robust Visual Odometry in HDR Environments，2017

（1）直接求和$M_{\mathrm{sum}}=\sum_{\mathbf{u}_{i} \in \mathrm{I}} G\left(\mathbf{u}_{i}\right)$
（2）对数求和$M_{\mathrm{shim}}=\sum_{\mathbf{u}_{i} \in \mathrm{I}} m_{\mathbf{u}_{i}}$其中$m_{\mathbf{u}_{i}}=\left\{\begin{array}{ll} {\frac{1}{N} \log \left(\lambda\left(\tilde{G}\left(\mathbf{u}_{i}\right)-\sigma\right)+1\right),} & {G\left(\mathbf{u}_{i}\right) \geq \sigma} \\ {0,} & {G\left(\mathbf{u}_{i}\right)<\sigma} \end{array}\right.$这种评价标准在下一篇论文中作更加详细的分析。

（3）百分位数$M_{\mathrm{perc}}(p)=\text { percentile }\left(\left\{G\left(\mathbf{u}_{i}\right)\right\}_{\mathbf{u}_{i} \in \mathrm{I}}, p\right)$其中，$\text { percentile }$函数是求百分位数，例如当参数 $p$ 为0.5时，那么$M_{\mathrm{perc}}(p)$就是所有梯度幅值中的中位数。

（4）软百分位数$M_{\text {softperc }}(p)=\sum_{i \in[0, S]} W_{i \mathrm{h}}(p) \cdot G_{i \mathrm{th}}$其中$S$为图像中所有像素的数量，$G_{i \mathrm{th}}$为排好序的梯度幅值，而权重$W_{i \mathrm{h}}$定义如下：$W_{i \mathrm{h}}=\left\{\begin{array}{ll} {\frac{1}{N} \sin \left(\frac{\pi}{2[p \cdot S]} i\right)^{k},} & {i \leq\lfloor p \cdot S\rfloor} \\ {\frac{1}{N} \sin \left(\frac{\pi}{2}-\frac{\pi}{2} \frac{i-\lfloor p \cdot S\rfloor}{S-\lfloor p \cdot S\rfloor}\right)^{k},} & {i>\lfloor p \cdot S\rfloor} \end{array}\right.$其中符号$\lfloor\cdot\rfloor$为向下取整。

## 曝光算法

2016-05-31 14:25:31 u011043491 阅读数 4455
• ###### 数字成像系统

数字成像系统暨Image signal processor原理培训，涵盖成像系统基础5讲：1.... ISP 信号处理基础，以及ISP各模块：6.黑电平与线性化7.Green Imbalance8：9.坏点消除等21讲，3A技术以及图像质量评价与调校6讲

34课时 949分钟 9072人学习 姜卓
免费试看

brightness = 1 - e-light

(light hitting film) = (light entering camera) * K

brightness = 1 - e-(light hitting film)

function Expose(float light, float exposure)

return ( 1 - exp(light * exposure) )  *  255


end function

main procedure:

for every pixel on the screen

calculate the amount of light entering the camera for this pixel, by Ray Tracing or whatever
call this value L

PixelValue = Expose(L, K)

plot this pixel with a brightness of PixelValue

end of loop


end of main procedure

The Virtual Darkroom http://tangle.seas.gwu.edu/~geigel/vdr/

## 自动曝光修复算法 附完整C代码

2018-06-02 15:55:00 weixin_33985679 阅读数 480
• ###### 数字成像系统

数字成像系统暨Image signal processor原理培训，涵盖成像系统基础5讲：1.... ISP 信号处理基础，以及ISP各模块：6.黑电平与线性化7.Green Imbalance8：9.坏点消除等21讲，3A技术以及图像质量评价与调校6讲

34课时 949分钟 9072人学习 姜卓
免费试看

AF自动对焦(Automatic Focus)

AE自动曝光(Automatic Exposure)

AW自动白平衡(Automatic White Balance)

matlab代码如下:

% Read the image

% Seperate the Channels
R=A(:,:,1);
G=A(:,:,2);
B=A(:,:,3);

% Calculate Intensity Component
I=(R+G+B)/3;

% Invert the image
I_inverted=255-I;

% Apply Average Filter to obtain the Mask Image
h_average=fspecial('average',15);
M=imfilter(I_inverted,h_average);

% Color Correction for R channel
R_new=zeros(size(R));
[c_y, c_x,~] = size(R);
for j = 1:c_x
for i = 1:c_y
p=double(R(i,j));
q=double(M(i,j));
R_new(i,j,:)=int8(255*((p/255)^(2^((128-q)/128))));
end
end

% Color Correction for G channel
G_new=zeros(size(G));
[c_y, c_x,~] = size(G);
for j = 1:c_x
for i = 1:c_y
p=double(G(i,j));
q=double(M(i,j));
G_new(i,j,:)=int8(255*((p/255)^(2^((128-q)/128))));
end
end

% Color Correction for B channel
B_new=zeros(size(B));
[c_y, c_x,~] = size(B);
for j = 1:c_x
for i = 1:c_y
p=double(B(i,j));
q=double(M(i,j));
B_new(i,j,:)=int8(255*((p/255)^(2^((128-q)/128))));
end
end

% Output Image
O=zeros(size(A));
O(:,:,1)=R_new;
O(:,:,2)=G_new;
O(:,:,3)=B_new;

% Convert the double output image to uint8
O=uint8(O);

% Plot the images
subplot(1,3,1), imshow(A), title('Original Image');
subplot(1,3,3), imshow(O), title('Output Image');

void LocalColorCorrection(unsigned char *Input, unsigned char *Output, int Width, int Height, int Channels) {
unsigned char *Mask = (unsigned char *) malloc(Width * Height * sizeof(unsigned char));
return;
unsigned char LocalLut[256 * 256];
unsigned char *pLocalLut = LocalLut + (mask << 8);
for (int pix = 0; pix < 256; ++pix) {
pLocalLut[pix] = ClampToByte(255.0f * powf(pix / 255.0f, powf(2.0f, (128.0f - mask) / 128.0f)));
}
}
InvertGrayscale(Input, Output, Width, Height, Channels);
int Radius = (MAX(Width, Height) / 512) + 1;
for (int Y = 0; Y < Height; Y++) {
unsigned char *pOutput = Output + (Y * Width * Channels);
unsigned char *pInput = Input + (Y * Width * Channels);
for (int X = 0; X < Width; X++) {
unsigned char *pLocalLut = LocalLut + (pMask[X] << 8);
for (int C = 0; C < Channels; C++) {
pOutput[C] = pLocalLut[pInput[C]];
}
pOutput += Channels;
pInput += Channels;
}
}
}

/**
*implmentation of Local Color Correction using Non-Linear Masking published by Nathan Moroney Hewlett-Packard Laboratories, Palo Alto, California.
**/
#include "browse.h"

#define USE_SHELL_OPEN

#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION

#include "stb_image.h"
/* ref:https://github.com/nothings/stb/blob/master/stb_image.h */
#define TJE_IMPLEMENTATION

#include "tiny_jpeg.h"
/* ref:https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h */
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include "timing.h"
#include <stdint.h>
#include <assert.h>

#ifndef _MAX_DRIVE
#define _MAX_DRIVE 3
#endif
#ifndef _MAX_FNAME
#define _MAX_FNAME 256
#endif
#ifndef _MAX_EXT
#define _MAX_EXT 256
#endif
#ifndef _MAX_DIR
#define _MAX_DIR 256
#endif
#ifndef MIN
#define MIN(a, b)    ( (a) > (b) ? (b) : (a) )
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
char saveFile[1024];

unsigned char *loadImage(const char *filename, int *Width, int *Height, int *Channels) {
return (stbi_load(filename, Width, Height, Channels, 0));
}

void saveImage(const char *filename, int Width, int Height, int Channels, unsigned char *Output) {
memcpy(saveFile + strlen(saveFile), filename, strlen(filename));
*(saveFile + strlen(saveFile) + 1) = 0;

if (!tje_encode_to_file(saveFile, Width, Height, Channels, true, Output)) {
fprintf(stderr, "save JPEG fail.\n");
return;
}
#ifdef USE_SHELL_OPEN
browse(saveFile);
#endif
}

void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
const char *end;
const char *p;
const char *s;
if (path[0] && path[1] == ':') {
if (drv) {
*drv++ = *path++;
*drv++ = *path++;
*drv = '\0';
}
} else if (drv)
*drv = '\0';
for (end = path; *end && *end != ':';)
end++;
for (p = end; p > path && *--p != '\\' && *p != '/';)
if (*p == '.') {
end = p;
break;
}
if (ext)
for (s = end; (*ext = *s++);)
ext++;
for (p = end; p > path;)
if (*--p == '\\' || *p == '/') {
p++;
break;
}
if (name) {
for (s = p; s < end;)
*name++ = *s++;
*name = '\0';
}
if (dir) {
for (s = path; s < p;)
*dir++ = *s++;
*dir = '\0';
}
}

void getCurrentFilePath(const char *filePath, char *saveFile) {
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
splitpath(filePath, drive, dir, fname, ext);
size_t n = strlen(filePath);
memcpy(saveFile, filePath, n);
char *cur_saveFile = saveFile + (n - strlen(ext));
cur_saveFile[0] = '_';
cur_saveFile[1] = 0;
}

int GetMirrorPos(int Length, int Pos) {
if (Pos < 0)
return -Pos;
else if (Pos >= Length)
return Length + Length - Pos - 2;
else
return Pos;
}

unsigned char ClampToByte(int Value) {
if (Value < 0)
return 0;
else if (Value > 255)
return 255;
else
return (unsigned char) Value;
}

void FillLeftAndRight_Mirror(int *Array, int Length, int Radius) {
for (int X = 0; X < Radius; X++) {
Array[Radius + Length + X] = Array[Radius + Length - X - 2];
}
}

int SumOfArray(const int *Array, int Length) {
int Sum = 0;
for (int X = 0; X < Length; X++) {
Sum += Array[X];
}
return Sum;
}

void BoxBlurGrayscale(unsigned char *input, unsigned char *output, int Width, int Height, int Radius) {
if ((input == NULL) || (output == NULL)) return;
if ((Width <= 0) || (Height <= 0) || (Radius <= 0)) return;
int SampleAmount = (2 * Radius + 1) * (2 * Radius + 1);
float Inv = 1.0f / SampleAmount;

int *ColValue = (int *) malloc((Width + Radius + Radius) * sizeof(int));
int *ColOffset = (int *) malloc((Height + Radius + Radius) * sizeof(int));
if ((ColValue == NULL) || (ColOffset == NULL)) {
if (ColValue != NULL) free(ColValue);
if (ColOffset != NULL) free(ColOffset);
return;
}
for (int Y = 0; Y < Height + Radius + Radius; Y++)
ColOffset[Y] = GetMirrorPos(Height, Y - Radius);
{
for (int Y = 0; Y < Height; Y++) {
unsigned char *scanLineOut = output + Y * Width;
if (Y == 0) {
memset(ColValue + Radius, 0, Width * sizeof(int));
unsigned char *scanLineIn = input + ColOffset[Z + Radius] * Width;
for (int X = 0; X < Width; X++) {
}
}
} else {
unsigned char *RowMoveOut = input + ColOffset[Y - 1] * Width;
unsigned char *RowMoveIn = input + ColOffset[Y + Radius + Radius] * Width;
for (int X = 0; X < Width; X++) {
RowMoveOut[X] - RowMoveIn[X];
}
}
int LastSum = SumOfArray(ColValue, Radius * 2 + 1);
scanLineOut[0] = ClampToByte((int) (LastSum * Inv));
for (int X = 0 + 1; X < Width; X++) {
int NewSum = LastSum - ColValue[X - 1] + ColValue[X + Radius + Radius];
scanLineOut[X] = ClampToByte((int) (NewSum * Inv));
LastSum = NewSum;
}
}
}
free(ColValue);
free(ColOffset);
}

void InvertGrayscale(unsigned char *Input, unsigned char *Output, int Width, int Height, int Channels) {
if (Channels == 1) {
for (unsigned int Y = 0; Y < Height; Y++) {
unsigned char *pOutput = Output + (Y * Width);
unsigned char *pInput = Input + (Y * Width);
for (unsigned int X = 0; X < Width; X++) {
pOutput[X] = (unsigned char) (255 - pInput[X]);
}
}
} else {
for (unsigned int Y = 0; Y < Height; Y++) {
unsigned char *pOutput = Output + (Y * Width);
unsigned char *pInput = Input + (Y * Width * Channels);
for (unsigned int X = 0; X < Width; X++) {
pOutput[X] = (unsigned char) (255 - ClampToByte(
(21842 * pInput[0] + 21842 * pInput[1] + 21842 * pInput[2]) >> 16));
pInput += Channels;
}
}
}
}

void LocalColorCorrection(unsigned char *Input, unsigned char *Output, int Width, int Height, int Channels) {
unsigned char *Mask = (unsigned char *) malloc(Width * Height * sizeof(unsigned char));
return;
unsigned char LocalLut[256 * 256];
unsigned char *pLocalLut = LocalLut + (mask << 8);
for (int pix = 0; pix < 256; ++pix) {
pLocalLut[pix] = ClampToByte(255.0f * powf(pix / 255.0f, powf(2.0f, (128.0f - mask) / 128.0f)));
}
}
InvertGrayscale(Input, Output, Width, Height, Channels);
int Radius = (MAX(Width, Height) / 512) + 1;
for (int Y = 0; Y < Height; Y++) {
unsigned char *pOutput = Output + (Y * Width * Channels);
unsigned char *pInput = Input + (Y * Width * Channels);
for (int X = 0; X < Width; X++) {
unsigned char *pLocalLut = LocalLut + (pMask[X] << 8);
for (int C = 0; C < Channels; C++) {
pOutput[C] = pLocalLut[pInput[C]];
}
pOutput += Channels;
pInput += Channels;
}
}
}

int main(int argc, char **argv) {
printf("Local Color Correction demo\n ");
printf("blog:http://cpuimage.cnblogs.com/ \n ");

if (argc < 2) {
printf("usage: %s   image \n ", argv[0]);
printf("eg: %s   d:\\image.jpg \n ", argv[0]);

return (0);
}
char *szfile = argv[1];

getCurrentFilePath(szfile, saveFile);

int Width = 0;
int Height = 0;
int Channels = 0;
unsigned char *inputImage = NULL;

double startTime = now();
inputImage = loadImage(szfile, &Width, &Height, &Channels);

if ((Channels != 0) && (Width != 0) && (Height != 0)) {
unsigned char *outputImg = (unsigned char *) stbi__malloc(Width * Channels * Height * sizeof(unsigned char));
if (inputImage) {
memcpy(outputImg, inputImage, (size_t) (Width * Channels * Height));
} else {
}
startTime = now();
LocalColorCorrection(inputImage, outputImg, Width, Height, Channels);
double nProcessTime = calcElapsed(startTime, now());

printf("process time: %d ms.\n ", (int) (nProcessTime * 1000));

startTime = now();

saveImage("done.jpg", Width, Height, Channels, outputImg);
double nSaveTime = calcElapsed(startTime, now());

printf("save time: %d ms.\n ", (int) (nSaveTime * 1000));

if (outputImg) {
stbi_image_free(outputImg);
}

if (inputImage) {
stbi_image_free(inputImage);
}
} else {
}

getchar();
printf("press any key to exit. \n");

return (EXIT_SUCCESS);
}

gaozhihan@vip.qq.com