Welcome to mirror list, hosted at ThFree Co, Russian Federation.

filter_nlm_gpu.h « filter « cycles « intern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 195fa15ed9c378b94f45753b181c8c97efecc9c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * Copyright 2011-2017 Blender Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CCL_NAMESPACE_BEGIN

ccl_device_inline void kernel_filter_nlm_calc_difference(int x, int y, int dx, int dy, float ccl_readonly_ptr weightImage, float ccl_readonly_ptr varianceImage, float *differenceImage, int4 rect, int w, int channel_offset, float a, float k_2)
{
	float diff = 0.0f;
	int numChannels = channel_offset? 3 : 1;
	for(int c = 0; c < numChannels; c++) {
		float cdiff = weightImage[c*channel_offset + y*w+x] - weightImage[c*channel_offset + (y+dy)*w+(x+dx)];
		float pvar = varianceImage[c*channel_offset + y*w+x];
		float qvar = varianceImage[c*channel_offset + (y+dy)*w+(x+dx)];
		diff += (cdiff*cdiff - a*(pvar + min(pvar, qvar))) / (1e-8f + k_2*(pvar+qvar));
	}
	if(numChannels > 1) {
		diff *= 1.0f/numChannels;
	}
	differenceImage[y*w+x] = diff;
}

ccl_device_inline void kernel_filter_nlm_blur(int x, int y, float ccl_readonly_ptr differenceImage, float *outImage, int4 rect, int w, int f)
{
	float sum = 0.0f;
	const int low = max(rect.y, y-f);
	const int high = min(rect.w, y+f+1);
	for(int y1 = low; y1 < high; y1++) {
		sum += differenceImage[y1*w+x];
	}
	sum *= 1.0f/(high-low);
	outImage[y*w+x] = sum;
}

ccl_device_inline void kernel_filter_nlm_calc_weight(int x, int y, float ccl_readonly_ptr differenceImage, float *outImage, int4 rect, int w, int f)
{
	float sum = 0.0f;
	const int low = max(rect.x, x-f);
	const int high = min(rect.z, x+f+1);
	for(int x1 = low; x1 < high; x1++) {
		sum += differenceImage[y*w+x1];
	}
	sum *= 1.0f/(high-low);
	outImage[y*w+x] = expf(-max(sum, 0.0f));
}

ccl_device_inline void kernel_filter_nlm_update_output(int x, int y,
                                                       int dx, int dy,
                                                       float ccl_readonly_ptr differenceImage,
                                                       float ccl_readonly_ptr image,
                                                       float *outImage, float *accumImage,
                                                       int4 rect, int w,
                                                       int f)
{
	float sum = 0.0f;
	const int low = max(rect.x, x-f);
	const int high = min(rect.z, x+f+1);
	for(int x1 = low; x1 < high; x1++) {
		sum += differenceImage[y*w+x1];
	}
	sum *= 1.0f/(high-low);
	if(outImage) {
		accumImage[y*w+x] += sum;
		outImage[y*w+x] += sum*image[(y+dy)*w+(x+dx)];
	}
	else {
		accumImage[y*w+x] = sum;
	}
}

ccl_device_inline void kernel_filter_nlm_construct_gramian(int fx, int fy,
                                                           int dx, int dy,
                                                           float ccl_readonly_ptr differenceImage,
                                                           float ccl_readonly_ptr buffer,
                                                           float *color_pass,
                                                           float *variance_pass,
                                                           float ccl_readonly_ptr transform,
                                                           int *rank,
                                                           float *XtWX,
                                                           float3 *XtWY,
                                                           int4 rect,
                                                           int4 filter_rect,
                                                           int w, int h, int f)
{
	int y = fy + filter_rect.y;
	int x = fx + filter_rect.x;
	const int low = max(rect.x, x-f);
	const int high = min(rect.z, x+f+1);
	float sum = 0.0f;
	for(int x1 = low; x1 < high; x1++) {
		sum += differenceImage[y*w+x1];
	}
	float weight = sum * (1.0f/(high - low));

	int storage_ofs = fy*filter_rect.z + fx;
	transform += storage_ofs;
	rank += storage_ofs;
	XtWX += storage_ofs;
	XtWY += storage_ofs;

	kernel_filter_construct_gramian(x, y,
	                                filter_rect.z*filter_rect.w,
	                                dx, dy, w, h,
	                                buffer,
	                                color_pass, variance_pass,
	                                transform, rank,
	                                weight, XtWX, XtWY);
}

ccl_device_inline void kernel_filter_nlm_normalize(int x, int y, float *outImage, float ccl_readonly_ptr accumImage, int4 rect, int w)
{
	outImage[y*w+x] /= accumImage[y*w+x];
}

CCL_NAMESPACE_END