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
26
27using namespace armarx;
28
35
36void
38{
39 providerName = getProperty<std::string>("providerName").getValue();
40 usingImageProvider(providerName);
41
42 offeringTopic(getProperty<std::string>("DebugObserverName").getValue());
43 frameRate = getProperty<float>("Framerate").getValue();
44 thresholdLaplace = getProperty<float>("ThresholdLaplaceBlur").getValue();
45 thresholdPerceptual = getProperty<float>("ThresholdPerceptualBlur").getValue();
46}
47
48void
50{
51 std::unique_lock lock(imageMutex);
52
53 visionx::ImageProviderInfo imageProviderInfo = getImageProvider(providerName);
54 imageProviderPrx = getProxy<visionx::ImageProviderInterfacePrx>(providerName);
55
56 cameraImages = new CByteImage*[2];
57 cameraImages[0] = visionx::tools::createByteImage(imageProviderInfo);
58 cameraImages[1] = visionx::tools::createByteImage(imageProviderInfo);
59
60
62 getProperty<std::string>("DebugObserverName").getValue());
63
64 //enableResultImages(0, imageProviderPrx->getImageFormat().dimension, imageProviderPrx->getImageFormat().type);
65
66 seq = 0;
67}
68
69void
73
74void
76{
77 std::unique_lock lock(imageMutex);
78
79 if (!waitForImages(getProperty<std::string>("providerName").getValue(), 1000))
80 {
81 ARMARX_WARNING << "Timeout while waiting for camera images (>1000ms)";
82 return;
83 }
84
85 int numImages = getImages(cameraImages);
86
87 if (numImages == 0)
88 {
89 ARMARX_WARNING << "Didn't receive one image! Aborting!";
90 return;
91 }
92
93
94 IplImage* ppIplImages[1] = {IplImageAdaptor::Adapt(cameraImages[0])};
95
96 cv::Mat image = cv::cvarrToMat(ppIplImages[0]);
97
98 cv::Mat gray_image;
99 cv::cvtColor(image, gray_image, cv::COLOR_BGR2GRAY);
100
101 double blurrinessLaplaceVariance = laplaceVarianceBlurrinessMetric(gray_image);
102 double blurrinessPerceptualBlur = blurringPerceptual(gray_image);
103 double blurrinessMarziliano = blurringMarziliano(gray_image);
104
105 ARMARX_LOG << deactivateSpam(1) << "blurrinessLaplaceVariance: "
106 << ((blurrinessLaplaceVariance < thresholdLaplace) ? "Blurry" : "Not blurry")
107 << " Value: " << blurrinessLaplaceVariance;
108 ARMARX_LOG << deactivateSpam(1) << "blurrinessPerceptialBlur: "
109 << ((blurrinessPerceptualBlur > thresholdPerceptual) ? "Blurry" : "Not blurry")
110 << " Value: " << blurrinessPerceptualBlur;
111 ARMARX_LOG << deactivateSpam(1) << "blurrinessMarziliano: " << blurrinessMarziliano;
112
113 StringVariantBaseMap debugValues;
114 debugValues["BlurrinessValueLaplace"] = new Variant(blurrinessLaplaceVariance);
115 debugValues["BlurryLaplace"] = new Variant((blurrinessLaplaceVariance < thresholdLaplace));
116
117 debugValues["BlurrinessValuePerceptual"] = new Variant(blurrinessPerceptualBlur);
118 debugValues["BlurryPerceptual"] = new Variant((blurrinessPerceptualBlur > thresholdPerceptual));
119
120 debugValues["BlurrinessValueMarziliano"] = new Variant(blurrinessMarziliano);
121
122 debugValues["seq"] = new Variant((int)seq);
123 seq++;
124
125 debugObserver->setDebugChannel("BlurrinessMetric", debugValues);
126
127 CByteImage* resultImages[1] = {IplImageAdaptor::Adapt(ppIplImages[0])};
128 provideResultImages(resultImages);
129
130 if (frameRate > 0.0)
131 {
132 fpsCounter.assureFPS(frameRate);
133 }
134}
135
136/**
137 * @brief armarx::BlurrinessMetric::laplaceVarianceBlurrinessMetric
138 * 'LAPV' algorithm from Pech et al. (2000)
139 * decsai.ugr.es/vip/files/conferences/Autofocusing2000.pdf
140 * @param in Input image as matrix
141 * @return blurriness value
142 */
143double
144armarx::BlurrinessMetric::laplaceVarianceBlurrinessMetric(cv::Mat& in)
145{
146 cv::Mat out;
147 cv::Laplacian(in, out, CV_64F);
148
149 cv::Scalar mean, variance;
150 cv::meanStdDev(out, mean, variance);
151
152 return (variance.val[0] * variance.val[0]);
153}
154
155/**
156 * @brief blurringPerceptual
157 * @inproceedings{crete2007blur,
158 title={The blur effect: Perception and estimation with a new no-reference perceptual blur metric},
159 author={Cr{\'e}t{\'e}-Roffet, Fr{\'e}d{\'e}rique and Dolmiere, Thierry and Ladret, Patricia and Nicolas, Marina},
160 booktitle={SPIE Electronic Imaging Symposium Conf Human Vision and Electronic Imaging},
161 volume={12},
162 pages={EI--6492},
163 year={2007}
164 }
165 * @param src Input image as matrix
166 * @return blurriness value
167 */
168double
169armarx::BlurrinessMetric::blurringPerceptual(const cv::Mat& src)
170{
171 double blur_index = 0;
172
173 cv::Mat smoothV(src.rows, src.cols, CV_8UC1);
174 cv::Mat smoothH(src.rows, src.cols, CV_8UC1);
175 cv::blur(src, smoothV, cv::Size(1, 9));
176 cv::blur(src, smoothH, cv::Size(9, 1));
177
178
179 double difS_V = 0, difS_H = 0, difB_V = 0, difB_H = 0;
180 double somaV = 0, somaH = 0, varV = 0, varH = 0;
181
182 for (int i = 0; i < src.rows; ++i)
183 {
184
185 for (int j = 0; j < src.cols; ++j)
186 {
187
188 if (i >= 1)
189 {
190 difS_V = abs(src.at<uchar>(i, j) - src.at<uchar>(i - 1, j));
191 difB_V = abs(smoothV.at<uchar>(i, j) - smoothV.at<uchar>(i - 1, j));
192 }
193
194 if (j >= 1)
195 {
196 difS_H = abs(src.at<uchar>(i, j) - src.at<uchar>(i, j - 1));
197 difB_H = abs(smoothH.at<uchar>(i, j) - smoothH.at<uchar>(i, j - 1));
198 }
199
200 varV += cv::max(0.0, difS_V - difB_V);
201 varH += cv::max(0.0, difS_H - difB_H);
202 somaV += difS_V;
203 somaH += difS_H;
204 }
205 }
206
207 blur_index = cv::max((somaV - varV) / somaV, (somaH - varH) / somaH);
208
209 return blur_index;
210}
211
212/**
213 * @brief blurringMarziliano
214 * @ARTICLE{Marziliano04perceptualblur,
215 author = {Pina Marziliano and Frederic Dufaux and Stefan Winkler and Touradj Ebrahimi},
216 title = {Perceptual blur and ringing metrics: Application to JPEG2000,” Signal Process},
217 journal = {Image Commun},
218 year = {2004},
219 pages = {163--172} }
220 * @param src Input image as matrix
221 * @return blurriness value
222 */
223double
224armarx::BlurrinessMetric::blurringMarziliano(const cv::Mat& src)
225{
226 double blur_index = 0;
227
228 cv::Mat edges(src.rows, src.cols, CV_8UC1);
229 cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
230
231 cv::GaussianBlur(src, edges, cv::Size(3, 3), 0);
232 cv::morphologyEx(edges, edges, cv::MORPH_OPEN, element);
233 cv::morphologyEx(edges, edges, cv::MORPH_CLOSE, element);
234 cv::Sobel(edges, edges, CV_8UC1, 1, 0);
235
236 unsigned int edge_counter = 0;
237 int c_start;
238 int c_end;
239 int k;
240
241 uchar max = 0;
242 uchar min = 255;
243
244 int length = 0;
245
246 for (int i = 0; i < src.rows; ++i)
247 {
248 for (int j = 0; j < src.cols; ++j)
249 {
250
251 c_start = -1;
252 c_end = -1;
253
254 if (edges.at<uchar>(i, j) > 0)
255 {
256 edge_counter++;
257
258 /** Left side of the border */
259 if (j == 0)
260 {
261 c_start = 0;
262 }
263 else
264 {
265 /** Check the first derivate */
266 if ((src.at<uchar>(i, j - 1) - src.at<uchar>(i, j)) > 0)
267 {
268 k = j;
269 max = src.at<uchar>(i, k);
270 while ((max <= src.at<uchar>(i, k - 1)) && (k > 1))
271 {
272 k--;
273 max = src.at<uchar>(i, k);
274 c_start = k;
275 }
276 }
277 else /* (src.at<uchar>(i,j-1) - src.at<uchar>(i,j)) < 0 */
278 {
279 k = j;
280 min = src.at<uchar>(i, k);
281 while ((min >= src.at<uchar>(i, k - 1)) && (k > 1))
282 {
283 k--;
284 min = src.at<uchar>(i, k);
285 c_start = k;
286 }
287 }
288 }
289
290 /** Right side of the border */
291 if (j == (src.cols - 1))
292 {
293 c_end = src.cols - 1;
294 }
295 else
296 {
297 /** Check the first derivate */
298 if ((src.at<uchar>(i, j + 1) - src.at<uchar>(i, j)) > 0)
299 {
300 k = j;
301 max = src.at<uchar>(i, k);
302 while (max <= src.at<uchar>(i, k + 1))
303 {
304 k++;
305 max = src.at<uchar>(i, k);
306 c_end = k;
307 if (k == src.cols - 1)
308 {
309 break;
310 }
311 }
312 }
313 else /* (src.at<uchar>(i,j+1) - src.at<uchar>(i,j)) <= 0 */
314 {
315 k = j;
316 min = src.at<uchar>(i, k);
317 while (min >= src.at<uchar>(i, k + 1))
318 {
319 k++;
320 min = src.at<uchar>(i, k);
321 c_end = k;
322 if (k == src.cols - 1)
323 {
324 break;
325 }
326 }
327 }
328 }
329
330 assert((c_end - c_start) >= 0);
331 length += (c_end - c_start);
332
333 } /* if(edges.at<uchar>(i,j) > 0) */
334 }
335 }
336
337 if (edge_counter != 0)
338 {
339 blur_index = ((double)length) / edge_counter;
340 }
341 else
342 {
343 blur_index = 0;
344 }
345
346 return blur_index;
347}
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
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.
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.