@@ -10,9 +10,9 @@ use std::ops::Mul;
10
10
use crate :: buffer_:: { Gray16Image , GrayAlpha16Image , Rgb16Image , Rgba16Image } ;
11
11
use crate :: image:: { GenericImage , GenericImageView } ;
12
12
use crate :: imageops:: filter_1d:: {
13
- filter_1d_la, filter_1d_la_u16, filter_1d_plane, filter_1d_plane_u16 , filter_1d_rgb ,
14
- filter_1d_rgb_f32 , filter_1d_rgb_u16 , filter_1d_rgba , filter_1d_rgba_f32 , filter_1d_rgba_u16 ,
15
- FilterImageSize ,
13
+ filter_1d_la, filter_1d_la_f32 , filter_1d_la_u16, filter_1d_plane, filter_1d_plane_f32 ,
14
+ filter_1d_plane_u16 , filter_1d_rgb , filter_1d_rgb_f32 , filter_1d_rgb_u16 , filter_1d_rgba ,
15
+ filter_1d_rgba_f32 , filter_1d_rgba_u16 , FilterImageSize ,
16
16
} ;
17
17
use crate :: traits:: { Enlargeable , Pixel , Primitive } ;
18
18
use crate :: utils:: clamp;
@@ -1002,58 +1002,53 @@ pub fn blur<I: GenericImageView>(
1002
1002
where
1003
1003
I :: Pixel : ' static ,
1004
1004
{
1005
- let sigma = if sigma <= 0.0 { 1.0 } else { sigma } ;
1005
+ // let sigma = if sigma <= 0.0 { 1.0 } else { sigma };
1006
+ //
1007
+ // let mut method = Filter {
1008
+ // kernel: Box::new(|x| gaussian(x, sigma)),
1009
+ // support: 2.0 * sigma,
1010
+ // };
1011
+ //
1012
+ // let (width, height) = image.dimensions();
1013
+ // let is_empty = width == 0 || height == 0;
1014
+ //
1015
+ // if is_empty {
1016
+ // return ImageBuffer::new(width, height);
1017
+ // }
1018
+ //
1019
+ // // Keep width and height the same for horizontal and
1020
+ // // vertical sampling.
1021
+ // // Note: tmp is not necessarily actually Rgba
1022
+ // let tmp: Rgba32FImage = vertical_sample(image, height, &mut method);
1023
+ // horizontal_sample(&tmp, width, &mut method)
1024
+ gaussian_blur_indirect ( image, sigma)
1025
+ }
1006
1026
1007
- let mut method = Filter {
1008
- kernel : Box :: new ( |x| gaussian ( x, sigma) ) ,
1009
- support : 2.0 * sigma,
1010
- } ;
1027
+ fn get_gaussian_kernel_1d ( width : usize , sigma : f32 ) -> Vec < f32 > {
1028
+ let mut sum_norm: f32 = 0f32 ;
1029
+ let mut kernel = vec ! [ 0f32 ; width] ;
1030
+ let scale = 1f32 / ( f32:: sqrt ( 2f32 * f32:: consts:: PI ) * sigma) ;
1031
+ let mean = ( width / 2 ) as f32 ;
1011
1032
1012
- let ( width, height) = image. dimensions ( ) ;
1013
- let is_empty = width == 0 || height == 0 ;
1033
+ for ( x, weight) in kernel. iter_mut ( ) . enumerate ( ) {
1034
+ let new_weight = f32:: exp ( -0.5f32 * f32:: powf ( ( x as f32 - mean) / sigma, 2.0f32 ) ) * scale;
1035
+ * weight = new_weight;
1036
+ sum_norm += new_weight;
1037
+ }
1014
1038
1015
- if is_empty {
1016
- return ImageBuffer :: new ( width, height) ;
1039
+ if sum_norm != 0f32 {
1040
+ let sum_scale = 1f32 / sum_norm;
1041
+ for weight in kernel. iter_mut ( ) {
1042
+ * weight = weight. mul ( sum_scale) ;
1043
+ }
1017
1044
}
1018
1045
1019
- // Keep width and height the same for horizontal and
1020
- // vertical sampling.
1021
- // Note: tmp is not necessarily actually Rgba
1022
- let tmp: Rgba32FImage = vertical_sample ( image, height, & mut method) ;
1023
- horizontal_sample ( & tmp, width, & mut method)
1046
+ kernel
1024
1047
}
1025
1048
1026
1049
/// In previous implementation sigma means radius, which is not the same one
1027
- pub fn gaussian_blur_dyn_image ( image : & DynamicImage , radius : f32 ) -> DynamicImage {
1028
- fn get_sigma_size ( kernel_size : usize ) -> f32 {
1029
- 0.3f32 * ( ( kernel_size as f32 - 1. ) * 0.5f32 - 1f32 ) + 0.8f32
1030
- }
1031
-
1032
- fn get_gaussian_kernel_1d ( width : usize , sigma : f32 ) -> Vec < f32 > {
1033
- let mut sum_norm: f32 = 0f32 ;
1034
- let mut kernel = vec ! [ 0f32 ; width] ;
1035
- let scale = 1f32 / ( f32:: sqrt ( 2f32 * f32:: consts:: PI ) * sigma) ;
1036
- let mean = ( width / 2 ) as f32 ;
1037
-
1038
- for ( x, weight) in kernel. iter_mut ( ) . enumerate ( ) {
1039
- let new_weight =
1040
- f32:: exp ( -0.5f32 * f32:: powf ( ( x as f32 - mean) / sigma, 2.0f32 ) ) * scale;
1041
- * weight = new_weight;
1042
- sum_norm += new_weight;
1043
- }
1044
-
1045
- if sum_norm != 0f32 {
1046
- let sum_scale = 1f32 / sum_norm;
1047
- for weight in kernel. iter_mut ( ) {
1048
- * weight = weight. mul ( sum_scale) ;
1049
- }
1050
- }
1051
-
1052
- kernel
1053
- }
1054
-
1055
- let kernel_size = radius. max ( 1. ) as usize * 2 + 1 ;
1056
- let sigma = get_sigma_size ( kernel_size) ;
1050
+ pub ( crate ) fn gaussian_blur_dyn_image ( image : & DynamicImage , sigma : f32 ) -> DynamicImage {
1051
+ let kernel_size = sigma. max ( 1. ) as usize * 2 + 1 ;
1057
1052
let gaussian_kernel = get_gaussian_kernel_1d ( kernel_size, sigma) ;
1058
1053
1059
1054
let filter_image_size = FilterImageSize {
@@ -1205,6 +1200,149 @@ pub fn gaussian_blur_dyn_image(image: &DynamicImage, radius: f32) -> DynamicImag
1205
1200
}
1206
1201
}
1207
1202
1203
+ pub ( crate ) fn gaussian_blur_indirect < I : GenericImageView > (
1204
+ image : & I ,
1205
+ sigma : f32 ,
1206
+ ) -> ImageBuffer < I :: Pixel , Vec < <I :: Pixel as Pixel >:: Subpixel > >
1207
+ where
1208
+ I :: Pixel : ' static ,
1209
+ {
1210
+ match I :: Pixel :: CHANNEL_COUNT {
1211
+ 1 => gaussian_blur_indirect_impl :: < I , 1 > ( image, sigma) ,
1212
+ 2 => gaussian_blur_indirect_impl :: < I , 2 > ( image, sigma) ,
1213
+ 3 => gaussian_blur_indirect_impl :: < I , 3 > ( image, sigma) ,
1214
+ 4 => gaussian_blur_indirect_impl :: < I , 4 > ( image, sigma) ,
1215
+ _ => unimplemented ! ( ) ,
1216
+ }
1217
+ }
1218
+
1219
+ fn gaussian_blur_indirect_impl < I : GenericImageView , const CN : usize > (
1220
+ image : & I ,
1221
+ sigma : f32 ,
1222
+ ) -> ImageBuffer < I :: Pixel , Vec < <I :: Pixel as Pixel >:: Subpixel > >
1223
+ where
1224
+ I :: Pixel : ' static ,
1225
+ {
1226
+ let mut transient = vec ! [ 0f32 ; image. width( ) as usize * image. height( ) as usize * CN ] ;
1227
+ for ( pixel, dst) in image. pixels ( ) . zip ( transient. chunks_exact_mut ( CN ) ) {
1228
+ let px = pixel. 2 . channels ( ) ;
1229
+ match CN {
1230
+ 1 => {
1231
+ dst[ 0 ] = NumCast :: from ( px[ 0 ] ) . unwrap ( ) ;
1232
+ }
1233
+ 2 => {
1234
+ dst[ 0 ] = NumCast :: from ( px[ 0 ] ) . unwrap ( ) ;
1235
+ dst[ 1 ] = NumCast :: from ( px[ 1 ] ) . unwrap ( ) ;
1236
+ }
1237
+ 3 => {
1238
+ dst[ 0 ] = NumCast :: from ( px[ 0 ] ) . unwrap ( ) ;
1239
+ dst[ 1 ] = NumCast :: from ( px[ 1 ] ) . unwrap ( ) ;
1240
+ dst[ 2 ] = NumCast :: from ( px[ 2 ] ) . unwrap ( ) ;
1241
+ }
1242
+ 4 => {
1243
+ dst[ 0 ] = NumCast :: from ( px[ 0 ] ) . unwrap ( ) ;
1244
+ dst[ 1 ] = NumCast :: from ( px[ 1 ] ) . unwrap ( ) ;
1245
+ dst[ 2 ] = NumCast :: from ( px[ 2 ] ) . unwrap ( ) ;
1246
+ dst[ 3 ] = NumCast :: from ( px[ 3 ] ) . unwrap ( ) ;
1247
+ }
1248
+ _ => unreachable ! ( ) ,
1249
+ }
1250
+ }
1251
+
1252
+ let mut transient_dst = vec ! [ 0f32 ; image. width( ) as usize * image. height( ) as usize * CN ] ;
1253
+
1254
+ let kernel_size = sigma. max ( 1. ) as usize * 2 + 1 ;
1255
+ let gaussian_kernel = get_gaussian_kernel_1d ( kernel_size, sigma) ;
1256
+
1257
+ let filter_image_size = FilterImageSize {
1258
+ width : image. width ( ) as usize ,
1259
+ height : image. height ( ) as usize ,
1260
+ } ;
1261
+
1262
+ match CN {
1263
+ 1 => {
1264
+ filter_1d_plane_f32 (
1265
+ & transient,
1266
+ & mut transient_dst,
1267
+ filter_image_size,
1268
+ & gaussian_kernel,
1269
+ & gaussian_kernel,
1270
+ )
1271
+ . unwrap ( ) ;
1272
+ }
1273
+ 2 => {
1274
+ filter_1d_la_f32 (
1275
+ & transient,
1276
+ & mut transient_dst,
1277
+ filter_image_size,
1278
+ & gaussian_kernel,
1279
+ & gaussian_kernel,
1280
+ )
1281
+ . unwrap ( ) ;
1282
+ }
1283
+ 3 => {
1284
+ filter_1d_rgb_f32 (
1285
+ & transient,
1286
+ & mut transient_dst,
1287
+ filter_image_size,
1288
+ & gaussian_kernel,
1289
+ & gaussian_kernel,
1290
+ )
1291
+ . unwrap ( ) ;
1292
+ }
1293
+ 4 => {
1294
+ filter_1d_rgba_f32 (
1295
+ & transient,
1296
+ & mut transient_dst,
1297
+ filter_image_size,
1298
+ & gaussian_kernel,
1299
+ & gaussian_kernel,
1300
+ )
1301
+ . unwrap ( ) ;
1302
+ }
1303
+ _ => unreachable ! ( ) ,
1304
+ }
1305
+
1306
+ let mut out = ImageBuffer :: new ( image. width ( ) , image. height ( ) ) ;
1307
+ for ( dst, src) in out. pixels_mut ( ) . zip ( transient_dst. chunks_exact_mut ( CN ) ) {
1308
+ match CN {
1309
+ 1 => {
1310
+ let v0 = NumCast :: from ( FloatNearest ( src[ 0 ] ) ) . unwrap ( ) ;
1311
+ #[ allow( deprecated) ]
1312
+ let t = Pixel :: from_channels ( v0, v0, v0, v0) ;
1313
+ * dst = t;
1314
+ }
1315
+ 2 => {
1316
+ let v0 = NumCast :: from ( FloatNearest ( src[ 0 ] ) ) . unwrap ( ) ;
1317
+ let v1 = NumCast :: from ( FloatNearest ( src[ 1 ] ) ) . unwrap ( ) ;
1318
+ #[ allow( deprecated) ]
1319
+ let t = Pixel :: from_channels ( v0, v1, v0, v0) ;
1320
+ * dst = t;
1321
+ }
1322
+ 3 => {
1323
+ let v0 = NumCast :: from ( FloatNearest ( src[ 0 ] ) ) . unwrap ( ) ;
1324
+ let v1 = NumCast :: from ( FloatNearest ( src[ 1 ] ) ) . unwrap ( ) ;
1325
+ let v2 = NumCast :: from ( FloatNearest ( src[ 2 ] ) ) . unwrap ( ) ;
1326
+ #[ allow( deprecated) ]
1327
+ let t = Pixel :: from_channels ( v0, v1, v2, v0) ;
1328
+ * dst = t;
1329
+ }
1330
+ 4 => {
1331
+ let v0 = NumCast :: from ( FloatNearest ( src[ 0 ] ) ) . unwrap ( ) ;
1332
+ let v1 = NumCast :: from ( FloatNearest ( src[ 1 ] ) ) . unwrap ( ) ;
1333
+ let v2 = NumCast :: from ( FloatNearest ( src[ 2 ] ) ) . unwrap ( ) ;
1334
+ let v3 = NumCast :: from ( FloatNearest ( src[ 3 ] ) ) . unwrap ( ) ;
1335
+ #[ allow( deprecated) ]
1336
+ let t = Pixel :: from_channels ( v0, v1, v2, v3) ;
1337
+ * dst = t;
1338
+ }
1339
+ _ => unreachable ! ( ) ,
1340
+ }
1341
+ }
1342
+
1343
+ out
1344
+ }
1345
+
1208
1346
/// Performs an unsharpen mask on the supplied image.
1209
1347
/// ```sigma``` is the amount to blur the image by.
1210
1348
/// ```threshold``` is the threshold for minimal brightness change that will be sharpened.
0 commit comments