This is the 17th day of my participation in Gwen Challenge

Unreal rendering

Non Photorealistic Rendering (NPR) refers to the use of computer simulation of various visual art Rendering styles, also used to develop new Rendering styles. For example, it simulates Chinese painting, watercolor, sketch, oil painting, printmaking and other artistic styles. NPR can also render 3d scenes into rich, special new visuals, making it innovative. NPR rendering is applied in animation, game and other entertainment fields with strong art form, and also appears in engineering and industrial design drawings. Broad application fields, not only because of its rich and diverse forms of artistic expression, but also because the computer can assist to complete the original workload, high difficulty of the creation work. At present, there are quite a number of NPR renderers based on 3D software, such as FinalToon, IL-Lustrator, Pencil, etc. At the same time, program mapping can also be used to create NPR materials to help generate hand-drawn style image effects. In addition, plugins like Mental Ray,Reyes, And Brazil are all solutions to NPR rendering

[Baidu Baike]

API

OpenCV provides us with four scenarios for non-realistic rendering: edge retention filtering, detail enhancement, sketch pencil drawing, and stylization.

Edge retention filtering

public static void edgePreservingFilter(Mat src, Mat dst, int flags, float sigma_s, float sigma_r)
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.

  • Parameter two: DST, output image, 8-bit three-channel.

  • Parameter 3: flags, edge reserved flag bit.

    public static final int
            RECURS_FILTER = 1,
            NORMCONV_FILTER = 2;
    Copy the code
  • Parameter 4: sigMA_s, neighborhood size. The value of 0 ~ 200.

  • Parameter 5: sigma_r, the degree of color difference averaged in the neighborhood. The value 0 ~ 1.

Detail enhancement

public static void detailEnhance(Mat src, Mat dst, float sigma_s, float sigma_r)
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.

  • Parameter two: DST, output image, 8-bit three-channel.

  • Parameter 3: sigMA_s, neighborhood size. The value of 0 ~ 200.

  • Parameter 4: sigma_r, the degree of color insimilarity averaged in the neighborhood. The value 0 ~ 1.

Sketch pencil drawing

public static void pencilSketch(Mat src, Mat dst1, Mat dst2, float sigma_s, float sigma_r, float shade_factor)
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.

  • Parameter 2: DST1, output image, 8-bit single channel, namely black and white sketch.

  • Parameter 3: DST2, output image, size type and input image is the same, namely color sketch.

  • Parameter 4: sigMA_s, neighborhood size. The value of 0 ~ 200.

  • Parameter 5: sigma_r, the degree of color difference averaged in the neighborhood. The value 0 ~ 1.

  • Parameter 6: shade_factor, intensity scaling value. The value 0 ~ 0.1

stylized

public static void stylization(Mat src, Mat dst, float sigma_s, float sigma_r) 
Copy the code
  • Parameter 1: SRC, input image, 8-bit three-channel.

  • Parameter two: DST, output image, 8-bit three-channel.

  • Parameter 3: sigMA_s, neighborhood size. The value of 0 ~ 200.

  • Parameter 4: sigma_r, the degree of color insimilarity averaged in the neighborhood. The value 0 ~ 1.

About SIGMA_S and SIGMA_R:

Sigma_s, Sigma_Spatial, determines the amount of smoothing. Sigma_r, Sigma_Range, determines the average.

A typical smoothing filter replaces the pixel value with a weighted sum of its adjacent pixels. The larger the neighborhood, the smoother the filtered image looks. The size of the neighborhood is proportional to the parameter SIGma_s. But in the edge retention filter, there are two key points: 1) smoothing the image; 2) Uneven edges/color boundaries. In other words, we can’t simply replace the pixel values with a weighted sum of the neighborhood pixels. Instead, the method of selecting pixels close to the current pixel value in the neighborhood, taking the average value, and replacing the current pixel value can avoid the above problems. So you need two parameters to specify the range and color similarity.

operation

/** * Not real render **@author yidong
 * @date11/30/20 * /
class NonPhotoRealisticRenderingActivity : AppCompatActivity() {

    private lateinit var mRgb: Mat
    private val mBinding: ActivityNonPhotorealisticRenderingBinding by lazy {
        ActivityNonPhotorealisticRenderingBinding.inflate(layoutInflater)
    }

    private var sigmaR = 10f
        set(value) {
            field = when {
                value > 200f- > {200f
                }
                value < 0f- > {200f
                }
                else -> {
                    value
                }
            }
            mBinding.tvSigmaR.text = sigmaR.toInt().toString(10)}private var sigmaS = 0.1 f
        set(value) {
            field = when {
                value > 1.0 f- > {1.0 f
                }
                value < 0f- > {0f
                }
                else -> {
                    value
                }
            }
            mBinding.tvSigmaS.text = String.format("%.1f", sigmaS)
        }

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

        mRgb = Mat()
        val bgr = Utils.loadResource(this, R.drawable.cow)
        Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)
        mBinding.ivLena.showMat(mRgb)
    }


    private fun doEdgePreservingFilter(flag: Int) {
        val dst = Mat()
        mBinding.isLoading = true
        GlobalScope.launch(Dispatchers.IO) {
            Photo.edgePreservingFilter(mRgb, dst, flag, sigmaR, sigmaS)
            launch(Dispatchers.Main) {
                mBinding.isLoading = false
                mBinding.ivResult.showMat(dst)
            }
        }
    }

    private fun doDetailEnhance(a) {
        val dst = Mat()
        mBinding.isLoading = true
        GlobalScope.launch(Dispatchers.IO) {
            Photo.detailEnhance(mRgb, dst, sigmaR, sigmaS)
            launch(Dispatchers.Main) {
                mBinding.isLoading = false
                mBinding.ivResult.showMat(dst)
            }
        }
    }


    private fun doPencilSketch(a) {
        val dst1 = Mat()
        val dst2 = Mat()
        mBinding.isLoading = true
        GlobalScope.launch(Dispatchers.IO) {
            Photo.pencilSketch(mRgb, dst1, dst2, sigmaR, sigmaS, 0.03 f)
            launch(Dispatchers.Main) {
                mBinding.isLoading = false
                mBinding.ivResult.showMat(dst2)
            }
        }
    }

    private fun doStylization(a) {
        val dst = Mat()
        mBinding.isLoading = true
        GlobalScope.launch(Dispatchers.IO) {
            Photo.stylization(mRgb, dst, sigmaR, sigmaS)
            launch(Dispatchers.Main) {
                mBinding.isLoading = false
                mBinding.ivResult.showMat(dst)
            }
        }
    }

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

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        title = item.title
        when(item.itemId) { R.id.photo_edge_preserving_normconv_filter -> { doEdgePreservingFilter(Photo.NORMCONV_FILTER) } R.id.photo_edge_preserving_recurs_filter -> { doEdgePreservingFilter(Photo.RECURS_FILTER) } R.id.photo_detail_enhance ->  { doDetailEnhance() } R.id.photo_pencil_sketch -> { doPencilSketch() } R.id.photo_stylization -> { doStylization() } }return true
    }

    fun incSigmaR(view: View) {
        this.sigmaR = this.sigmaR.plus(1.0 f)
        if (this.sigmaR > 200.0 f) {
            this.sigmaR = 200f}}fun decSigmaR(view: View) {
        this.sigmaR = this.sigmaR.minus(1.0 f)
        if (this.sigmaR < 0f) {
            this.sigmaR = 0f}}fun incSigmaS(view: View) {
        this.sigmaS = this.sigmaS.plus(.1f)
        if (this.sigmaS > 1.0 f) {
            this.sigmaS = 1f}}fun decSigmaS(view: View) {
        this.sigmaS = this.sigmaS.minus(.1f)
        if (this.sigmaS < 0f) {
            this.sigmaS = 0f}}}Copy the code

The effect

The source code

Github.com/onlyloveyd/…