BlurrinessMetric.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package VisionX::ArmarXObjects::BlurrinessMetric
17 * @author David Sippel ( uddoe at student dot kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "BlurrinessMetric.h"
24
27
28using namespace armarx;
29
36
37void
39{
40 providerName = getProperty<std::string>("providerName").getValue();
41 usingImageProvider(providerName);
42
43 offeringTopic(getProperty<std::string>("DebugObserverName").getValue());
44 frameRate = getProperty<float>("Framerate").getValue();
45 thresholdLaplace = getProperty<float>("ThresholdLaplaceBlur").getValue();
46 thresholdPerceptual = getProperty<float>("ThresholdPerceptualBlur").getValue();
47}
48
49void
51{
52 std::unique_lock lock(imageMutex);
53
54 visionx::ImageProviderInfo imageProviderInfo = getImageProvider(providerName);
55 imageProviderPrx = getProxy<visionx::ImageProviderInterfacePrx>(providerName);
56
57 cameraImages = new CByteImage*[2];
58 cameraImages[0] = visionx::tools::createByteImage(imageProviderInfo);
59 cameraImages[1] = visionx::tools::createByteImage(imageProviderInfo);
60
61
63 getProperty<std::string>("DebugObserverName").getValue());
64
65 //enableResultImages(0, imageProviderPrx->getImageFormat().dimension, imageProviderPrx->getImageFormat().type);
66
67 seq = 0;
68}
69
70void
74
75void
77{
78 std::unique_lock lock(imageMutex);
79
80 if (!waitForImages(getProperty<std::string>("providerName").getValue(), 1000))
81 {
82 ARMARX_WARNING << "Timeout while waiting for camera images (>1000ms)";
83 return;
84 }
85
86 int numImages = getImages(cameraImages);
87
88 if (numImages == 0)
89 {
90 ARMARX_WARNING << "Didn't receive one image! Aborting!";
91 return;
92 }
93
94
95 IplImage* ppIplImages[1] = {IplImageAdaptor::Adapt(cameraImages[0])};
96
97 cv::Mat image = cv::cvarrToMat(ppIplImages[0]);
98
99 cv::Mat gray_image;
100 cv::cvtColor(image, gray_image, cv::COLOR_BGR2GRAY);
101
102 double blurrinessLaplaceVariance = laplaceVarianceBlurrinessMetric(gray_image);
103 double blurrinessPerceptualBlur = blurringPerceptual(gray_image);
104 double blurrinessMarziliano = blurringMarziliano(gray_image);
105
106 ARMARX_LOG << deactivateSpam(1) << "blurrinessLaplaceVariance: "
107 << ((blurrinessLaplaceVariance < thresholdLaplace) ? "Blurry" : "Not blurry")
108 << " Value: " << blurrinessLaplaceVariance;
109 ARMARX_LOG << deactivateSpam(1) << "blurrinessPerceptialBlur: "
110 << ((blurrinessPerceptualBlur > thresholdPerceptual) ? "Blurry" : "Not blurry")
111 << " Value: " << blurrinessPerceptualBlur;
112 ARMARX_LOG << deactivateSpam(1) << "blurrinessMarziliano: " << blurrinessMarziliano;
113
114 StringVariantBaseMap debugValues;
115 debugValues["BlurrinessValueLaplace"] = new Variant(blurrinessLaplaceVariance);
116 debugValues["BlurryLaplace"] = new Variant((blurrinessLaplaceVariance < thresholdLaplace));
117
118 debugValues["BlurrinessValuePerceptual"] = new Variant(blurrinessPerceptualBlur);
119 debugValues["BlurryPerceptual"] = new Variant((blurrinessPerceptualBlur > thresholdPerceptual));
120
121 debugValues["BlurrinessValueMarziliano"] = new Variant(blurrinessMarziliano);
122
123 debugValues["seq"] = new Variant((int)seq);
124 seq++;
125
126 debugObserver->setDebugChannel("BlurrinessMetric", debugValues);
127
128 CByteImage* resultImages[1] = {IplImageAdaptor::Adapt(ppIplImages[0])};
129 provideResultImages(resultImages);
130
131 if (frameRate > 0.0)
132 {
133 fpsCounter.assureFPS(frameRate);
134 }
135}
136
137/**
138 * @brief armarx::BlurrinessMetric::laplaceVarianceBlurrinessMetric
139 * 'LAPV' algorithm from Pech et al. (2000)
140 * decsai.ugr.es/vip/files/conferences/Autofocusing2000.pdf
141 * @param in Input image as matrix
142 * @return blurriness value
143 */
144double
145armarx::BlurrinessMetric::laplaceVarianceBlurrinessMetric(cv::Mat& in)
146{
147 cv::Mat out;
148 cv::Laplacian(in, out, CV_64F);
149
150 cv::Scalar mean, variance;
151 cv::meanStdDev(out, mean, variance);
152
153 return (variance.val[0] * variance.val[0]);
154}
155
156/**
157 * @brief blurringPerceptual
158 * @inproceedings{crete2007blur,
159 title={The blur effect: Perception and estimation with a new no-reference perceptual blur metric},
160 author={Cr{\'e}t{\'e}-Roffet, Fr{\'e}d{\'e}rique and Dolmiere, Thierry and Ladret, Patricia and Nicolas, Marina},
161 booktitle={SPIE Electronic Imaging Symposium Conf Human Vision and Electronic Imaging},
162 volume={12},
163 pages={EI--6492},
164 year={2007}
165 }
166 * @param src Input image as matrix
167 * @return blurriness value
168 */
169double
170armarx::BlurrinessMetric::blurringPerceptual(const cv::Mat& src)
171{
172 double blur_index = 0;
173
174 cv::Mat smoothV(src.rows, src.cols, CV_8UC1);
175 cv::Mat smoothH(src.rows, src.cols, CV_8UC1);
176 cv::blur(src, smoothV, cv::Size(1, 9));
177 cv::blur(src, smoothH, cv::Size(9, 1));
178
179
180 double difS_V = 0, difS_H = 0, difB_V = 0, difB_H = 0;
181 double somaV = 0, somaH = 0, varV = 0, varH = 0;
182
183 for (int i = 0; i < src.rows; ++i)
184 {
185
186 for (int j = 0; j < src.cols; ++j)
187 {
188
189 if (i >= 1)
190 {
191 difS_V = abs(src.at<uchar>(i, j) - src.at<uchar>(i - 1, j));
192 difB_V = abs(smoothV.at<uchar>(i, j) - smoothV.at<uchar>(i - 1, j));
193 }
194
195 if (j >= 1)
196 {
197 difS_H = abs(src.at<uchar>(i, j) - src.at<uchar>(i, j - 1));
198 difB_H = abs(smoothH.at<uchar>(i, j) - smoothH.at<uchar>(i, j - 1));
199 }
200
201 varV += cv::max(0.0, difS_V - difB_V);
202 varH += cv::max(0.0, difS_H - difB_H);
203 somaV += difS_V;
204 somaH += difS_H;
205 }
206 }
207
208 blur_index = cv::max((somaV - varV) / somaV, (somaH - varH) / somaH);
209
210 return blur_index;
211}
212
213/**
214 * @brief blurringMarziliano
215 * @ARTICLE{Marziliano04perceptualblur,
216 author = {Pina Marziliano and Frederic Dufaux and Stefan Winkler and Touradj Ebrahimi},
217 title = {Perceptual blur and ringing metrics: Application to JPEG2000,” Signal Process},
218 journal = {Image Commun},
219 year = {2004},
220 pages = {163--172} }
221 * @param src Input image as matrix
222 * @return blurriness value
223 */
224double
225armarx::BlurrinessMetric::blurringMarziliano(const cv::Mat& src)
226{
227 double blur_index = 0;
228
229 cv::Mat edges(src.rows, src.cols, CV_8UC1);
230 cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
231
232 cv::GaussianBlur(src, edges, cv::Size(3, 3), 0);
233 cv::morphologyEx(edges, edges, cv::MORPH_OPEN, element);
234 cv::morphologyEx(edges, edges, cv::MORPH_CLOSE, element);
235 cv::Sobel(edges, edges, CV_8UC1, 1, 0);
236
237 unsigned int edge_counter = 0;
238 int c_start;
239 int c_end;
240 int k;
241
242 uchar max = 0;
243 uchar min = 255;
244
245 int length = 0;
246
247 for (int i = 0; i < src.rows; ++i)
248 {
249 for (int j = 0; j < src.cols; ++j)
250 {
251
252 c_start = -1;
253 c_end = -1;
254
255 if (edges.at<uchar>(i, j) > 0)
256 {
257 edge_counter++;
258
259 /** Left side of the border */
260 if (j == 0)
261 {
262 c_start = 0;
263 }
264 else
265 {
266 /** Check the first derivate */
267 if ((src.at<uchar>(i, j - 1) - src.at<uchar>(i, j)) > 0)
268 {
269 k = j;
270 max = src.at<uchar>(i, k);
271 while ((max <= src.at<uchar>(i, k - 1)) && (k > 1))
272 {
273 k--;
274 max = src.at<uchar>(i, k);
275 c_start = k;
276 }
277 }
278 else /* (src.at<uchar>(i,j-1) - src.at<uchar>(i,j)) < 0 */
279 {
280 k = j;
281 min = src.at<uchar>(i, k);
282 while ((min >= src.at<uchar>(i, k - 1)) && (k > 1))
283 {
284 k--;
285 min = src.at<uchar>(i, k);
286 c_start = k;
287 }
288 }
289 }
290
291 /** Right side of the border */
292 if (j == (src.cols - 1))
293 {
294 c_end = src.cols - 1;
295 }
296 else
297 {
298 /** Check the first derivate */
299 if ((src.at<uchar>(i, j + 1) - src.at<uchar>(i, j)) > 0)
300 {
301 k = j;
302 max = src.at<uchar>(i, k);
303 while (max <= src.at<uchar>(i, k + 1))
304 {
305 k++;
306 max = src.at<uchar>(i, k);
307 c_end = k;
308 if (k == src.cols - 1)
309 {
310 break;
311 }
312 }
313 }
314 else /* (src.at<uchar>(i,j+1) - src.at<uchar>(i,j)) <= 0 */
315 {
316 k = j;
317 min = src.at<uchar>(i, k);
318 while (min >= src.at<uchar>(i, k + 1))
319 {
320 k++;
321 min = src.at<uchar>(i, k);
322 c_end = k;
323 if (k == src.cols - 1)
324 {
325 break;
326 }
327 }
328 }
329 }
330
331 assert((c_end - c_start) >= 0);
332 length += (c_end - c_start);
333
334 } /* if(edges.at<uchar>(i,j) > 0) */
335 }
336 }
337
338 if (edge_counter != 0)
339 {
340 blur_index = ((double)length) / edge_counter;
341 }
342 else
343 {
344 blur_index = 0;
345 }
346
347 return blur_index;
348}
349
350namespace armarx
351{
353} // namespace armarx
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
Brief description of class BlurrinessMetric.
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
void onExitImageProcessor() override
Exit the ImapeProcessor component.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void process() override
Process the vision component.
void onInitImageProcessor() override
Setup the vision component.
static std::string GetDefaultName()
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
The Variant class is described here: Variants.
Definition Variant.h:224
void usingImageProvider(std::string name)
Registers a delayed topic subscription and a delayed provider proxy retrieval which all will be avail...
bool waitForImages(int milliseconds=1000)
Wait for new images.
ImageProviderInfo getImageProvider(std::string name, ImageType destinationImageType=eRgb, bool waitForProxy=false)
Select an ImageProvider.
int getImages(CByteImage **ppImages)
Poll images from provider.
void provideResultImages(CByteImage **images, armarx::MetaInfoSizeBasePtr info=nullptr)
sends result images for visualization
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_LOG
Definition Logging.h:165
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
std::map< std::string, VariantBasePtr > StringVariantBaseMap
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > abs(const std::vector< T > &v)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
CByteImage * createByteImage(const ImageFormatInfo &imageFormat, const ImageType imageType)
Creates a ByteImage for the destination type specified in the given imageProviderInfo.