Commit 0cdcf4baf3e1465a707bee67c5e63a8ec47e5758
1 parent
47078a75
Somewhat more robust AdjacentOverlay
Fix some issues with bounding boxes not being clipped correctly. If the overlay would go past the image boundary, expand the image instead of clipping.
Showing
1 changed file
with
120 additions
and
8 deletions
openbr/plugins/draw.cpp
| ... | ... | @@ -271,14 +271,27 @@ class AdjacentOverlayTransform : public Transform |
| 271 | 271 | void project(const Template &src, Template &dst) const |
| 272 | 272 | { |
| 273 | 273 | dst = src; |
| 274 | + | |
| 274 | 275 | if (imgName.isEmpty() || targetName.isEmpty() || !dst.file.contains(imgName) || !dst.file.contains(targetName)) |
| 275 | 276 | return; |
| 276 | 277 | |
| 277 | - QString im_name = src.file.get<QString>(imgName); | |
| 278 | + QVariant temp = src.file.value(imgName); | |
| 279 | + cv::Mat im; | |
| 280 | + // is this a filename? | |
| 281 | + if (temp.canConvert<QString>()) { | |
| 282 | + QString im_name = temp.toString(); | |
| 283 | + Template temp_im; | |
| 284 | + opener->project(File(im_name), temp_im); | |
| 285 | + im = temp_im.m(); | |
| 286 | + } | |
| 287 | + // a cv::Mat ? | |
| 288 | + else if (temp.canConvert<cv::Mat>()) | |
| 289 | + im = src.file.get<cv::Mat>(imgName); | |
| 290 | + else | |
| 291 | + qDebug() << "Unrecognized property type " << imgName << "for" << src.file.name; | |
| 292 | + | |
| 293 | + // Location of detected face in source image | |
| 278 | 294 | QRectF target_location = src.file.get<QRectF>(targetName); |
| 279 | - Template temp_im; | |
| 280 | - opener->project(File(im_name), temp_im); | |
| 281 | - cv::Mat im = temp_im.m(); | |
| 282 | 295 | |
| 283 | 296 | // match width with target region |
| 284 | 297 | qreal target_width = target_location.width(); |
| ... | ... | @@ -290,39 +303,137 @@ class AdjacentOverlayTransform : public Transform |
| 290 | 303 | |
| 291 | 304 | cv::resize(im, im, cv::Size(target_width, target_height)); |
| 292 | 305 | |
| 306 | + // ROI used to maybe crop the matched image | |
| 293 | 307 | cv::Rect clip_roi; |
| 294 | 308 | clip_roi.x = 0; |
| 295 | 309 | clip_roi.y = 0; |
| 296 | 310 | clip_roi.width = im.cols; |
| 297 | - clip_roi.height= im.rows; | |
| 311 | + clip_roi.height= im.rows <= dst.m().rows ? im.rows : dst.m().rows; | |
| 298 | 312 | |
| 299 | 313 | int half_width = src.m().cols / 2; |
| 300 | 314 | int out_x = 0; |
| 315 | + | |
| 316 | + // place in the source image we will copy the matched image to. | |
| 301 | 317 | cv::Rect target_roi; |
| 318 | + bool left_side = false; | |
| 319 | + int width_adjust = 0; | |
| 302 | 320 | // Place left |
| 303 | 321 | if (target_location.center().rx() > half_width) { |
| 304 | 322 | out_x = target_location.left() - im.cols; |
| 305 | 323 | if (out_x < 0) { |
| 306 | - clip_roi.width += out_x; | |
| 324 | + width_adjust = abs(out_x); | |
| 307 | 325 | out_x = 0; |
| 308 | 326 | } |
| 327 | + left_side = true; | |
| 309 | 328 | } |
| 310 | 329 | // place right |
| 311 | 330 | else { |
| 312 | 331 | out_x = target_location.right(); |
| 313 | 332 | int high = out_x + im.cols; |
| 314 | 333 | if (high >= src.m().cols) { |
| 315 | - clip_roi.width -= high - src.m().cols + 1; | |
| 334 | + width_adjust = abs(high - src.m().cols + 1); | |
| 316 | 335 | } |
| 317 | 336 | } |
| 337 | + | |
| 338 | + cv::Mat outIm; | |
| 339 | + if (width_adjust) | |
| 340 | + { | |
| 341 | + outIm.create(dst.m().rows, dst.m().cols + width_adjust, CV_8UC3); | |
| 342 | + memset(outIm.data, 127, outIm.rows * outIm.cols * outIm.channels()); | |
| 343 | + | |
| 344 | + Rect temp; | |
| 345 | + | |
| 346 | + if (left_side) | |
| 347 | + temp = Rect(abs(width_adjust), 0, dst.m().cols, dst.m().rows); | |
| 348 | + | |
| 349 | + else | |
| 350 | + temp = Rect(0, 0, dst.m().cols, dst.m().rows); | |
| 351 | + | |
| 352 | + dst.m().copyTo(outIm(temp)); | |
| 353 | + | |
| 354 | + } | |
| 355 | + else | |
| 356 | + outIm = dst.m(); | |
| 357 | + | |
| 358 | + if (clip_roi.height + target_location.top() >= outIm.rows) | |
| 359 | + { | |
| 360 | + clip_roi.height -= abs(outIm.rows - (clip_roi.height + target_location.top() )); | |
| 361 | + } | |
| 362 | + if (clip_roi.x + clip_roi.width >= im.cols) { | |
| 363 | + clip_roi.width -= abs(im.cols - (clip_roi.x + clip_roi.width + 1)); | |
| 364 | + if (clip_roi.width < 0) | |
| 365 | + clip_roi.width = 1; | |
| 366 | + } | |
| 367 | + | |
| 368 | + if (clip_roi.y + clip_roi.height >= im.rows) { | |
| 369 | + clip_roi.height -= abs(im.rows - (clip_roi.y + clip_roi.height + 1)); | |
| 370 | + } | |
| 371 | + if (clip_roi.x < 0) | |
| 372 | + clip_roi.x = 0; | |
| 373 | + if (clip_roi.y < 0) | |
| 374 | + clip_roi.y = 0; | |
| 375 | + | |
| 376 | + if (clip_roi.height < 0) | |
| 377 | + clip_roi.height = 0; | |
| 378 | + | |
| 379 | + if (clip_roi.width < 0) | |
| 380 | + clip_roi.width = 0; | |
| 381 | + | |
| 382 | + | |
| 383 | + if (clip_roi.y + clip_roi.height >= im.rows) | |
| 384 | + { | |
| 385 | + qDebug() << "Bad clip y" << clip_roi.y + clip_roi.height << im.rows; | |
| 386 | + } | |
| 387 | + if (clip_roi.x + clip_roi.width >= im.cols) | |
| 388 | + { | |
| 389 | + qDebug() << "Bad clip x" << clip_roi.x + clip_roi.width << im.cols; | |
| 390 | + } | |
| 391 | + | |
| 392 | + if (clip_roi.y < 0 || clip_roi.height < 0) | |
| 393 | + { | |
| 394 | + qDebug() << "bad clip y, low" << clip_roi.y << clip_roi.height; | |
| 395 | + qFatal("die"); | |
| 396 | + } | |
| 397 | + if (clip_roi.x < 0 || clip_roi.width < 0) | |
| 398 | + { | |
| 399 | + qDebug() << "bad clip x, low" << clip_roi.x << clip_roi.width; | |
| 400 | + qFatal("die"); | |
| 401 | + } | |
| 402 | + | |
| 318 | 403 | target_roi.x = out_x; |
| 319 | 404 | target_roi.width = clip_roi.width; |
| 320 | 405 | target_roi.y = target_location.top(); |
| 321 | 406 | target_roi.height = clip_roi.height; |
| 322 | 407 | |
| 408 | + | |
| 323 | 409 | im = im(clip_roi); |
| 324 | 410 | |
| 325 | - cv::Mat outIm = dst.m(); | |
| 411 | + if (target_roi.x < 0 || target_roi.x >= outIm.cols) | |
| 412 | + { | |
| 413 | + qDebug() << "Bad xdim in targetROI!" << target_roi.x << " out im x: " << outIm.cols; | |
| 414 | + qFatal("die"); | |
| 415 | + } | |
| 416 | + | |
| 417 | + if (target_roi.x + target_roi.width < 0 || (target_roi.x + target_roi.width) >= outIm.cols) | |
| 418 | + { | |
| 419 | + qDebug() << "Bad xdim in targetROI!" << target_roi.x + target_roi.width; | |
| 420 | + qFatal("die"); | |
| 421 | + } | |
| 422 | + | |
| 423 | + if (target_roi.y < 0 || target_roi.y >= outIm.rows) | |
| 424 | + { | |
| 425 | + qDebug() << "Bad ydim in targetROI!" << target_roi.y; | |
| 426 | + qFatal("die"); | |
| 427 | + } | |
| 428 | + | |
| 429 | + if ((target_roi.y + target_roi.height) < 0 || (target_roi.y + target_roi.height) > outIm.rows) | |
| 430 | + { | |
| 431 | + qDebug() << "Bad ydim in targetROI!" << target_roi.y + target_roi.height; | |
| 432 | + qDebug() << "target_roi.y: " << target_roi.y << " height: " << target_roi.height; | |
| 433 | + qFatal("die"); | |
| 434 | + } | |
| 435 | + | |
| 436 | + | |
| 326 | 437 | std::vector<cv::Mat> channels; |
| 327 | 438 | cv::split(outIm, channels); |
| 328 | 439 | |
| ... | ... | @@ -335,6 +446,7 @@ class AdjacentOverlayTransform : public Transform |
| 335 | 446 | } |
| 336 | 447 | cv::merge(channels, outIm); |
| 337 | 448 | dst.m() = outIm; |
| 449 | + | |
| 338 | 450 | } |
| 339 | 451 | |
| 340 | 452 | void init() | ... | ... |