| 329 | } |
| 330 | |
| 331 | int VideoThumbnailer::getBestThumbnailIndex(vector<VideoFrame>& videoFrames, const vector<Histogram<int>>& histograms) |
| 332 | { |
| 333 | Histogram<float> avgHistogram; |
| 334 | for (auto&& histogram : histograms) { |
| 335 | for (int j = 0; j < 255; ++j) { |
| 336 | avgHistogram.r[j] += static_cast<float>(histogram.r[j]) / histograms.size(); |
| 337 | avgHistogram.g[j] += static_cast<float>(histogram.g[j]) / histograms.size(); |
| 338 | avgHistogram.b[j] += static_cast<float>(histogram.b[j]) / histograms.size(); |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | int bestFrame = -1; |
| 343 | float minRMSE = FLT_MAX; |
| 344 | for (size_t i = 0; i < histograms.size(); ++i) { |
| 345 | // calculate root mean squared error |
| 346 | float rmse = 0.0; |
| 347 | for (int j = 0; j < 255; ++j) { |
| 348 | float error = fabsf(avgHistogram.r[j] - histograms[i].r[j]) + fabsf(avgHistogram.g[j] - histograms[i].g[j]) + fabsf(avgHistogram.b[j] - histograms[i].b[j]); |
| 349 | rmse += (error * error) / 255; |
| 350 | } |
| 351 | |
| 352 | rmse = sqrtf(rmse); |
| 353 | if (rmse < minRMSE) { |
| 354 | minRMSE = rmse; |
| 355 | bestFrame = i; |
| 356 | } |
| 357 | |
| 358 | #ifdef DEBUG_MODE |
| 359 | stringstream outputFile; |
| 360 | outputFile << "frames/Frame" << setfill('0') << setw(3) << i << "_" << rmse << endl; |
| 361 | std::unique_ptr<ImageWriter> imageWriter(ImageWriterFactory<const string&>::createImageWriter(Png, outputFile.str())); |
| 362 | vector<uint8_t*> rowPointers; |
| 363 | for (int x = 0; x < videoFrames[i].height; ++x) |
| 364 | rowPointers.push_back(&(videoFrames[i].frameData[x * videoFrames[i].lineSize])); |
| 365 | imageWriter->writeFrame(&(rowPointers.front()), videoFrames[i].width, videoFrames[i].height, m_ImageQuality); |
| 366 | #endif |
| 367 | } |
| 368 | |
| 369 | #ifdef DEBUG_MODE |
| 370 | cout << "Best frame was: " << bestFrame << "(RMSE: " << minRMSE << ")" << endl; |
| 371 | #endif |
| 372 | |
| 373 | return bestFrame; |
| 374 | } |
| 375 | |
| 376 | void VideoThumbnailer::TraceMessage(ThumbnailerLogLevel lvl, const std::string& msg) |
| 377 | { |
nothing calls this directly
no test coverage detected