]> git.sesse.net Git - casparcg/blob - modules/image/util/image_algorithms.h
Fixed build errors under windows
[casparcg] / modules / image / util / image_algorithms.h
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #pragma once
23
24 #include <common/tweener.h>
25
26 #include <cmath>
27 #include <cstdint>
28
29 namespace caspar { namespace image {
30
31 /**
32  * Helper for calculating the color of a pixel given any number of of other
33  * pixels (each with their own weight).
34  */
35 class rgba_weighting
36 {
37         int r = 0;
38         int g = 0;
39         int b = 0;
40         int a = 0;
41         int total_weight = 0;
42 public:
43         template<class RGBAPixel>
44         inline void add_pixel(const RGBAPixel& pixel, uint8_t weight)
45         {
46                 r += pixel.r() * weight;
47                 g += pixel.g() * weight;
48                 b += pixel.b() * weight;
49                 a += pixel.a() * weight;
50
51                 total_weight += weight;
52         }
53
54         template<class RGBAPixel>
55         inline void store_result(RGBAPixel& pixel)
56         {
57                 pixel.r() = static_cast<uint8_t>(r / total_weight);
58                 pixel.g() = static_cast<uint8_t>(g / total_weight);
59                 pixel.b() = static_cast<uint8_t>(b / total_weight);
60                 pixel.a() = static_cast<uint8_t>(a / total_weight);
61         }
62 };
63
64 template<class T>
65 std::vector<T> get_tweened_values(const caspar::tweener& tweener, size_t num_values, T from, T to)
66 {
67         std::vector<T> result;
68         result.reserve(num_values);
69
70         double start = static_cast<double>(from);
71         double delta = static_cast<double>(to - from);
72         double duration = static_cast<double>(num_values);
73
74         for (double t = 0; t < duration; ++t)
75         {
76                 result.push_back(static_cast<T>(tweener(t, start, delta, duration - 1.0)));
77         }
78
79         return std::move(result);
80 }
81
82 /**
83  * Blur a source image and store the blurred result in a destination image.
84  * <p>
85  * The blur is done by weighting each relative pixel from a destination pixel
86  * position using a vector of relative x-y pairs. The further away a related
87  * pixel is the less weight it gets. A tweener is used to calculate the actual
88  * weights of each related pixel.
89  *
90  * @param src                      The source view. Has to model the ImageView
91  *                                 concept and have a pixel type modelling the
92  *                                 RGBAPixel concept.
93  * @param dst                      The destination view. Has to model the
94  *                                 ImageView concept and have a pixel type
95  *                                 modelling the RGBAPixel concept.
96  * @param motion_trail_coordinates The relative x-y positions to weight in for
97  *                                 each pixel.
98  * @param tweener                  The tweener to use for calculating the
99  *                                 weights of each relative position in the
100  *                                 motion trail.
101  */
102 template<class SrcView, class DstView>
103 void blur(
104         const SrcView& src,
105         DstView& dst,
106         const std::vector<std::pair<int, int>>& motion_trail_coordinates, 
107         const caspar::tweener& tweener)
108 {
109         auto blur_px = motion_trail_coordinates.size();
110         auto tweened_weights_y = get_tweened_values<uint8_t>(tweener, blur_px + 2, 255, 0);
111         tweened_weights_y.pop_back();
112         tweened_weights_y.erase(tweened_weights_y.begin());
113
114         auto src_end = src.end();
115         auto dst_iter = dst.begin();
116
117         for (auto src_iter = src.begin(); src_iter != src_end; ++src_iter, ++dst_iter)
118         {
119                 rgba_weighting w;
120
121                 for (int i = 0; i < blur_px; ++i)
122                 {
123                         auto& coordinate = motion_trail_coordinates[i];
124                         auto other_pixel = src.relative(src_iter, coordinate.first, coordinate.second);
125
126                         if (other_pixel == nullptr)
127                                 break;
128
129                         w.add_pixel(*other_pixel, tweened_weights_y[i]);
130                 }
131
132                 w.add_pixel(*src_iter, 255);
133                 w.store_result(*dst_iter);
134         }
135 }
136
137 /**
138  * Calculate relative x-y coordinates of a straight line with a given angle and
139  * a given number of points.
140  *
141  * @param num_pixels    The number of pixels/points to create.
142  * @param angle_radians The angle of the line in radians.
143  *
144  * @return the x-y pairs.
145  */
146 std::vector<std::pair<int, int>> get_line_points(int num_pixels, double angle_radians);
147
148 /**
149  * Directionally blur a source image modelling the ImageView concept and store
150  * the blurred image to a destination image also modelling the ImageView
151  * concept.
152  * <p>
153  * The pixel type of the views must model the RGBAPixel concept.
154  *
155  * @param src           The source image view. Has to model the ImageView
156  *                      concept and have a pixel type that models RGBAPixel.
157  * @param dst           The destiation image view. Has to model the ImageView
158  *                      concept and have a pixel type that models RGBAPixel.
159  * @param angle_radians The angle in radians to directionally blur the image.
160  * @param blur_px       The number of pixels of the blur.
161  * @param tweener       The tweener to use to create a pixel weighting curve
162  *                      with.
163  */
164 template<class SrcView, class DstView>
165 void blur(
166         const SrcView& src,
167         DstView& dst,
168         double angle_radians,
169         int blur_px, 
170         const caspar::tweener& tweener)
171 {
172         auto motion_trail = get_line_points(blur_px, angle_radians);
173
174         blur(src, dst, motion_trail, tweener);
175 }
176
177 /**
178  * Premultiply with alpha for each pixel in an ImageView. The modifications is
179  * done in place. The pixel type of the ImageView must model the RGBAPixel
180  * concept.
181  *
182  * @param view_to_modify The image view to premultiply in place. Has to model
183  *                       the ImageView concept and have a pixel type that
184  *                       models RGBAPixel.
185  */
186 template<class SrcDstView>
187 void premultiply(SrcDstView& view_to_modify)
188 {
189         std::for_each(view_to_modify.begin(), view_to_modify.end(), [&](SrcDstView::pixel_type& pixel)
190         {
191                 int alpha = static_cast<int>(pixel.a());
192
193                 if (alpha != 255) // Performance optimization
194                 {
195                         // We don't event try to premultiply 0 since it will be unaffected.
196                         if (pixel.r())
197                                 pixel.r() = static_cast<uint8_t>(static_cast<int>(pixel.r()) * alpha / 255);
198
199                         if (pixel.g())
200                                 pixel.g() = static_cast<uint8_t>(static_cast<int>(pixel.g()) * alpha / 255);
201
202                         if (pixel.b())
203                                 pixel.b() = static_cast<uint8_t>(static_cast<int>(pixel.b()) * alpha / 255);
204                 }
205         });
206 }
207
208 }}