1 #include "stdafx.h"
2 #include "GaussBlur.h"
3
4
CGaussBlur()5 CGaussBlur::CGaussBlur()
6 {
7 }
8
9
~CGaussBlur()10 CGaussBlur::~CGaussBlur()
11 {
12 if (m_pTempl != NULL)
13 free(m_pTempl);
14 }
15
SetSigma(double sigma)16 void CGaussBlur::SetSigma(double sigma)
17 {
18 int i;
19 m_sigma = sigma;
20 m_r = (int)(m_sigma * 3 + 0.5);
21 if (m_r <= 0) m_r = 1;
22
23 //分配模板
24 LPVOID pOldTempl = m_pTempl;
25 m_pTempl = (double*)realloc(m_pTempl, sizeof(double) * (m_r + 1));
26
27 //分配失败?
28 if (m_pTempl == NULL)
29 {
30 if (pOldTempl != NULL)
31 free(pOldTempl);
32
33 return;
34 }
35
36 //计算 p[0] 灰度值为1 的模板面
37 double k1 = (double)((-0.5) / (m_sigma * m_sigma));
38 for (i = 0; i <= m_r; i++)
39 m_pTempl[i] = exp(k1 * i * i);
40
41 //计算模板加权总和
42 double sum = m_pTempl[0];
43 for (i = 1; i <= m_r; i++)
44 {
45 sum += (m_pTempl[i] * 2);
46 }
47
48 //归一化
49 sum = (double)(1.0 / sum); //取倒数
50 for (i = 0; i <= m_r; i++)
51 m_pTempl[i] *= sum;
52 }
53
Reset()54 void CGaussBlur::Reset()
55 {
56 m_r = -1;
57 m_sigma = (double)(-1.0);
58 if (m_pTempl != NULL)
59 {
60 free(m_pTempl);
61 m_pTempl = NULL;
62 }
63 }
64
DoGaussBlur(const CImage & image_src,CImage & image_dest)65 void CGaussBlur::DoGaussBlur(const CImage & image_src, CImage & image_dest)
66 {
67 if (image_src.IsNull())
68 return;
69 int width = image_src.GetWidth();
70 int height = image_src.GetHeight();
71 int bpp = image_src.GetBPP();
72 if (!image_dest.IsNull())
73 image_dest.Destroy();
74 image_dest.Create(width, height, bpp);
75 Filter(image_src.GetPixelAddress(0, height - 1), image_dest.GetPixelAddress(0, height - 1), width, height, bpp);
76 }
77
Filter(LPCVOID pSrc,LPVOID pDest,int width,int height,int bpp)78 bool CGaussBlur::Filter(LPCVOID pSrc, LPVOID pDest, int width, int height, int bpp)
79 {
80 if (pSrc == NULL || pDest == NULL)
81 return false;
82
83 //只能处理 8, 24, 32 bpp
84 if (bpp != 24 && bpp != 8 && bpp != 32)
85 return false;
86
87 if (m_r < 0 || m_pTempl == NULL)
88 return false;
89
90 int absHeight = (height >= 0) ? height : (-height);
91 int stride = (width * bpp + 31) / 32 * 4;
92 int pixelSize = bpp / 8;
93
94 //申请缓冲区,存储中间结果
95 LPVOID pTemp = malloc(stride * absHeight);
96 if (pTemp == NULL)
97 return false;
98
99 CGaussBlurThreadParams params;
100
101 params.pSrc = (LPBYTE)pSrc;
102 params.pDest = (LPBYTE)pTemp;
103 params.width = width;
104 params.height = absHeight;
105 params.stride = stride;
106 params.pixelSize = pixelSize;
107 params.r = m_r;
108 params.pTempl = m_pTempl;
109 params.rowBegin = 0;
110 params.rowEnd = absHeight;
111 params.bHorz = true;
112
113 if (bpp == 8)
114 GaussBlurThreadProc8(¶ms);
115 else
116 GaussBlurThreadProc24(¶ms);
117
118
119 params.pSrc = (LPBYTE)pTemp;
120 params.pDest = (LPBYTE)pDest;
121 params.bHorz = false;
122
123 if (bpp == 8)
124 GaussBlurThreadProc8(¶ms);
125 else
126 GaussBlurThreadProc24(¶ms);
127
128 free(pTemp);
129 return true;
130 }
131
GaussBlurThreadProc8(LPVOID lpParameters)132 DWORD CGaussBlur::GaussBlurThreadProc8(LPVOID lpParameters)
133 {
134 CGaussBlurThreadParams *pInfo = (CGaussBlurThreadParams*)lpParameters;
135
136 double result;
137 int row, col, subRow, subCol, MaxVal, x, x1;
138 LPINT pSubVal, pRefVal;
139
140 if (pInfo->bHorz)
141 {
142 //水平方向
143 pSubVal = &subCol;
144 pRefVal = &col;
145 MaxVal = pInfo->width - 1;
146 }
147 else
148 {
149 //垂直方向
150 pSubVal = &subRow;
151 pRefVal = &row;
152 MaxVal = pInfo->height - 1;
153 }
154
155 LPBYTE pSrcPixel = NULL;
156 LPBYTE pDestPixel = NULL;
157
158 for (row = pInfo->rowBegin; row < pInfo->rowEnd; ++row)
159 {
160 for (col = 0; col < pInfo->width; ++col)
161 {
162 pDestPixel = pInfo->pDest + pInfo->stride * row + col;
163
164 result = 0;
165
166 subRow = row;
167 subCol = col;
168
169 for (x = -pInfo->r; x <= pInfo->r; x++)
170 {
171 //边界处理
172 x1 = (x >= 0) ? x : (-x);
173 *pSubVal = *pRefVal + x;
174 if (*pSubVal < 0) *pSubVal = 0;
175 else if (*pSubVal > MaxVal) *pSubVal = MaxVal;
176
177 pSrcPixel = pInfo->pSrc + pInfo->stride * subRow + subCol;
178
179 result += *pSrcPixel * pInfo->pTempl[x1];
180 }
181 *pDestPixel = (BYTE)result;
182 }
183 }
184 return 0;
185 }
186
GaussBlurThreadProc24(LPVOID lpParameters)187 DWORD CGaussBlur::GaussBlurThreadProc24(LPVOID lpParameters)
188 {
189 CGaussBlurThreadParams *pInfo = (CGaussBlurThreadParams*)lpParameters;
190
191 double result[3];
192 int row, col, subRow, subCol, MaxVal, x, x1;
193 LPINT pSubVal, pRefVal;
194
195 if (pInfo->bHorz)
196 {
197 //水平方向
198 pSubVal = &subCol;
199 pRefVal = &col;
200 MaxVal = pInfo->width - 1;
201 }
202 else
203 {
204 //垂直方向
205 pSubVal = &subRow;
206 pRefVal = &row;
207 MaxVal = pInfo->height - 1;
208 }
209
210 LPBYTE pSrcPixel = NULL;
211 LPBYTE pDestPixel = NULL;
212
213 for (row = pInfo->rowBegin; row < pInfo->rowEnd; ++row)
214 {
215 for (col = 0; col < pInfo->width; ++col)
216 {
217 pDestPixel = pInfo->pDest + pInfo->stride * row + pInfo->pixelSize * col;
218
219 result[0] = 0;
220 result[1] = 0;
221 result[2] = 0;
222
223 subRow = row;
224 subCol = col;
225
226 for (x = -pInfo->r; x <= pInfo->r; x++)
227 {
228 x1 = (x >= 0) ? x : (-x);
229 *pSubVal = *pRefVal + x;
230
231 //边界处理:Photoshop 采用的是方法1。
232 //方法1:取边缘像素(图像边缘像素向内部扩散!)
233 if (*pSubVal < 0) *pSubVal = 0;
234 else if (*pSubVal > MaxVal) *pSubVal = MaxVal;
235
236 //方法2:取当前像素(使得越靠近图像边缘的地方越清晰)
237 /*
238 if(*pSubVal < 0 || *pSubVal > MaxVal)
239 *pSubVal = *pRefVal;
240 */
241
242 pSrcPixel = pInfo->pSrc + pInfo->stride * subRow + pInfo->pixelSize * subCol;
243
244 result[0] += pSrcPixel[0] * pInfo->pTempl[x1];
245 result[1] += pSrcPixel[1] * pInfo->pTempl[x1];
246 result[2] += pSrcPixel[2] * pInfo->pTempl[x1];
247 }
248 pDestPixel[0] = (BYTE)result[0];
249 pDestPixel[1] = (BYTE)result[1];
250 pDestPixel[2] = (BYTE)result[2];
251 }
252 }
253 return 0;
254 }
255