@@ -33,9 +33,11 @@ import org.opencv.core.Core.minMaxLoc
3333import org.opencv.core.CvType.*
3434import org.opencv.core.Mat
3535import org.opencv.core.MatOfInt
36+ import org.opencv.core.Scalar
3637import org.opencv.core.Size
3738import org.opencv.imgcodecs.Imgcodecs
3839import org.opencv.imgproc.Imgproc.*
40+ import org.opencv.xphoto.Xphoto
3941import java.io.File
4042import kotlin.math.PI
4143import kotlin.math.abs
@@ -240,7 +242,7 @@ class MainActivity : AppCompatActivity() {
240242 )
241243 )
242244
243- return true ;
245+ return true
244246 }
245247 }
246248
@@ -395,6 +397,7 @@ class MainActivity : AppCompatActivity() {
395397 binding.radioButtonPointDirectionAll.isEnabled = enabled
396398 binding.radioButtonPointDirectionHorizontal.isEnabled = enabled
397399 binding.radioButtonPointDirectionVertical.isEnabled = enabled
400+ binding.checkBoxInpaint.isEnabled = enabled
398401
399402 menuSave?.isEnabled = enabled
400403 menuPrevPerspective?.isEnabled = enabled && settings.prevHeight > 0
@@ -420,7 +423,7 @@ class MainActivity : AppCompatActivity() {
420423 private fun saveImageAsync () {
421424 if (inputImage.empty()) return
422425
423- warpImageAsync()
426+ warpImageAsync( binding.checkBoxInpaint.isChecked )
424427 if (outputImage.empty()) return
425428
426429 setBusyDialogTitleAsync(MSG_SAVE )
@@ -523,7 +526,7 @@ class MainActivity : AppCompatActivity() {
523526 }
524527 }
525528
526- private fun warpImageAsync () {
529+ private fun warpImageAsync ( inpaint : Boolean ) {
527530 if (inputImage.empty()) return
528531 if (! outputImage.empty()) return
529532
@@ -557,6 +560,14 @@ class MainActivity : AppCompatActivity() {
557560 val perspectiveMat = getPerspectiveTransform(srcMat, destMat)
558561 warpPerspective(inputImage, outputImage, perspectiveMat, inputImage.size(), INTER_LANCZOS4 )
559562
563+ if (inpaint) {
564+ val tmpMat = Mat (inputImage.width(), inputImage.height(), CV_8UC1 , Scalar (255.0 ))
565+ val warpedMask = Mat ()
566+ warpPerspective(tmpMat, warpedMask, perspectiveMat, inputImage.size(), INTER_NEAREST )
567+ Xphoto .inpaint( outputImage, warpedMask, tmpMat, Xphoto .INPAINT_SHIFTMAP )
568+ outputImage = tmpMat
569+ }
570+
560571 runOnUiThread {
561572 binding.imagePreview.setBitmap(matToBitmap(outputImage))
562573 }
@@ -566,8 +577,10 @@ class MainActivity : AppCompatActivity() {
566577 if (inputImage.empty()) return
567578 if (! outputImage.empty()) return
568579
580+ val inpaint = binding.checkBoxInpaint.isChecked
581+
569582 runAsync(MSG_WARP ) {
570- warpImageAsync()
583+ warpImageAsync(inpaint )
571584 }
572585 }
573586
@@ -755,6 +768,10 @@ class MainActivity : AppCompatActivity() {
755768 setContentView(binding.root)
756769 updateButtons()
757770
771+ binding.checkBoxInpaint.setOnCheckedChangeListener { _, _ ->
772+ clearOutputImage()
773+ }
774+
758775 binding.buttonReset.setOnClickListener {
759776 binding.imageEdit.resetPoints()
760777 }
0 commit comments