This is the 19th day of my participation in the Genwen Challenge

Poisson image editing

Image synthesis is a basic problem in image processing, which generates a new image by embedding an object or a region in the source image into the target image. In the process of image composition, in order to make the composite image more natural, the composite boundary should be seamless. However, if the original image and the target image have significantly different texture features, the directly synthesized image will have obvious boundaries. To solve this problem, Prez et al. proposed a method to solve the optimal pixel value by constructing Poisson equation, which can well fuse the background of source image and target image while preserving the gradient information of source image. The method solves a Poisson equation according to the boundary conditions specified by the user, and realizes the continuity on the gradient, so as to achieve the seamless fusion at the boundary. The main idea of Poisson image editing is to reconstruct the image pixels in the sum region by interpolation method according to the gradient information of the original image and the boundary information of the target image.

The principle of

Paper: Michel Gangnet, Patrick Perez, and Andrew Blake. Poisson Image Editing. In ACM Transactions on Graphics (TOG), Volume 22, Pages 313 — 318. ACM, 2003.

Paper, common explanation: blog.csdn.net/hjimce/arti…

API

Seamless cloning

public static void seamlessClone(Mat src, Mat dst, Mat mask, Point p, Mat blend, int flags)
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.
  • Parameter two: DST, input image, 8-bit three-channel.
  • Parameter 3: Mask, input image, 8-bit single channel or 8-bit three-channel.
  • Parameter 4: p, the center position of the cloned image on the DST image.
  • Parameter 5: Blend, output image. The size type is the same as DST.
  • Parameter 6: flags: indicates the flag of the clone mode.
public static final int... NORMAL_CLONE =1.// Insert the SRC object to be cloned completely into the DST target image image without changing its outline characteristics and structure
        MIXED_CLONE = 2.// Compared with normal clone, it will take the background color and texture into account, and achieve transparent channel blending of outline features and background.
        MONOCHROME_TRANSFER = 3.// Feature-based migration fusion only fuses features into the background image.
Copy the code

The three images are combined into one image, SRC and mask matting (logical and consistent in size), and the extracted image is fused to the P position in DST (the extracted image size ≤ DST). P is also the center of the graph.

Adjust the color

public static void colorChange(Mat src, Mat mask, Mat dst, float red_mul, float green_mul, float blue_mul)
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.
  • Parameter 2: Mask, input image, 8-bit single channel or 8-bit three-channel.
  • Parameter 3: DST, output image, size type is the same as SRC.
  • Parameter 4: RED_MUL, R channel multiplication coefficient.
  • Parameter 5: green_MUL, G channel multiplication factor.
  • Parameter 6: Blue_MUl, B channel multiplication factor.

Color adjust the area of interest.

To eliminate the highlighted

public static void illuminationChange(Mat src, Mat mask, Mat dst, float alpha, float beta)
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.
  • Parameter 2: Mask, input image, 8-bit single channel or 8-bit three-channel.
  • Parameter 3: DST, output image, size type is the same as SRC.
  • Parameter 4: alpha, 0-2.
  • Parameter 5: Beta, 0-2.

The two parameters alpha and beta jointly determine the blur degree of the image after highlight elimination (0~2 is clear, and 2 is fuzzy).

The texture is flat

public static void textureFlattening(Mat src, Mat mask, Mat dst, float low_threshold, float high_threshold, int kernel_size) 
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.
  • Parameter 2: Mask, input image, 8-bit single channel or 8-bit three-channel.
  • Parameter 3: DST, output image, size type is the same as SRC.
  • Parameter 4: low_threshold: a low threshold ranging from 0 to 100.
  • Parameter 5: high_threshold: a high threshold greater than 100.
  • Parameter 6: Kernel_size, size of Sobel core.

When the texture is flat, the fewer edges (the stronger the selectivity) the edge detector selects, the more sparse the edge mapping will be and the more obvious the flattening effect will be. The algorithm assumes that the color of the source image is close to the color of the target image. This assumption means that when the colors do not match, the color of the source image will tend to the color of the target image.

operation

** * Idong */ ** idong */
class PoissonImageEditActivity : AppCompatActivity() {

    private val mList = mutableListOf<ImageTextObject>()
    private lateinit var mAdapter: ImageTextAdapter

    private val mBinding: ActivityPoissonImageEditBinding by lazy {
        ActivityPoissonImageEditBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(mBinding.root)

        mAdapter = ImageTextAdapter(this, mList)
        mBinding.container.adapter = mAdapter
    }

    override fun onCreateOptionsMenu(menu: Menu?).: Boolean {
        menuInflater.inflate(R.menu.menu_cloning, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        title = item.title
        when (item.itemId) {
            R.id.normal_cloning -> {
                this.wrapCoroutine({ showLoading() }, { doNormalCloning() }, { hideLoading() })
            }
            R.id.mixed_cloning -> {
                this.wrapCoroutine({ showLoading() }, { doMixedCloning() }, { hideLoading() })
            }
            R.id.monochrome_transfer -> {
                this.wrapCoroutine({ showLoading() }, { doMonochromeTransfer() }, { hideLoading() })
            }
            R.id.local_color_change -> {
                this.wrapCoroutine({ showLoading() }, { doColorChange() }, { hideLoading() })
            }
            R.id.local_illumination_change -> {
                this.wrapCoroutine({ showLoading() }, { doIlluminationChange() }, { hideLoading() })
            }
            R.id.texture_flattening -> {
                this.wrapCoroutine({ showLoading() }, { doTextureFlattening() }, { hideLoading() })
            }
        }
        return true
    }

    private fun doNormalCloning(a) {
        val source = Utils.loadResource(this, R.drawable.normal_cloning_source)
        val mask = Utils.loadResource(this, R.drawable.normal_cloning_mask)
        val destination = Utils.loadResource(this, R.drawable.normal_cloning_destination)
        val result = Mat()
        val center = Point(400.toDouble(), 100.toDouble())
        Photo.seamlessClone(source, destination, mask, center, result, Photo.NORMAL_CLONE)

        mList.clear()
        mList.add(ImageTextObject(source.toRgb(), "source"))
        mList.add(ImageTextObject(mask, "mask"))
        mList.add(ImageTextObject(destination.toRgb(), "destination"))
        mList.add(ImageTextObject(result.toRgb(), "result"))}private fun doMixedCloning(a) {
        val source = Utils.loadResource(this, R.drawable.mixed_cloning_source)
        val mask = Utils.loadResource(this, R.drawable.mixed_cloning_mask)
        val destination = Utils.loadResource(this, R.drawable.mixed_cloning_destination)
        val result = Mat()
        val center = Point(destination.size().width / 2.0, destination.size().height / 2.0)
        Photo.seamlessClone(source, destination, mask, center, result, Photo.MIXED_CLONE)

        mList.clear()
        mList.add(ImageTextObject(source.toRgb(), "source"))
        mList.add(ImageTextObject(mask, "mask"))
        mList.add(ImageTextObject(destination.toRgb(), "destination"))
        mList.add(ImageTextObject(result.toRgb(), "result"))}private fun doMonochromeTransfer(a) {
        val source = Utils.loadResource(this, R.drawable.monochrome_transfer_source)
        val mask = Utils.loadResource(this, R.drawable.monochrome_transfer_mask)
        val destination = Utils.loadResource(this, R.drawable.monochrome_transfer_destination)
        val result = Mat()
        val center = Point(destination.size().width / 2.0, destination.size().height / 2.0)
        Photo.seamlessClone(source, destination, mask, center, result, Photo.MONOCHROME_TRANSFER)

        mList.clear()
        mList.add(ImageTextObject(source.toRgb(), "source"))
        mList.add(ImageTextObject(mask, "mask"))
        mList.add(ImageTextObject(destination.toRgb(), "destination"))
        mList.add(ImageTextObject(result.toRgb(), "result"))}private fun doColorChange(a) {
        val source = Utils.loadResource(this, R.drawable.color_change_source)
        val mask = Utils.loadResource(this, R.drawable.color_change_mask)
        val result = Mat()
        Photo.colorChange(source, mask, result, 1.5 F..5F..5F)

        mList.clear()
        mList.add(ImageTextObject(source.toRgb(), "source"))
        mList.add(ImageTextObject(mask, "mask"))
        mList.add(ImageTextObject(result.toRgb(), "result"))}private fun doIlluminationChange(a) {
        val source = Utils.loadResource(this, R.drawable.illumination_change_source)
        val mask = Utils.loadResource(this, R.drawable.illumination_change_mask)
        val result = Mat()
        Photo.illuminationChange(source, mask, result, 0.2 f.0.4 f)

        mList.clear()
        mList.add(ImageTextObject(source.toRgb(), "source"))
        mList.add(ImageTextObject(mask, "mask"))
        mList.add(ImageTextObject(result.toRgb(), "result"))}private fun doTextureFlattening(a) {
        val source = Utils.loadResource(this, R.drawable.texture_flattening_source)
        val mask = Utils.loadResource(this, R.drawable.texture_flattening_mask)
        val result = Mat()
        Photo.textureFlattening(source, mask, result, 30F.45F.3)

        mList.clear()
        mList.add(ImageTextObject(source.toRgb(), "source"))
        mList.add(ImageTextObject(mask, "mask"))
        mList.add(ImageTextObject(result.toRgb(), "result"))}private fun showLoading(a) {
        mBinding.isLoading = true
    }

    private fun hideLoading(a) {
        mAdapter.notifyDataSetChanged()
        mBinding.isLoading = false}}Copy the code

The effect






The source code

Github.com/onlyloveyd/…