Android用OpenCV实现非真实渲染的方法
更新:HHH   时间:2023-1-7


这篇文章主要讲解了“Android用OpenCV实现非真实渲染的方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android用OpenCV实现非真实渲染的方法”吧!

目录
  • 非真实渲染

  • API

    • 边缘保留滤波

    • 细节增强

    • 素描铅笔画

    • 风格化

  • 操作

    • 效果

      非真实渲染

      非真实感渲染(Non Photorealistic Rendering,简称NPR),是指利用计算机模拟各种视觉艺术的绘制风格,也用于发展新的绘制风格。比如模拟中国画、水彩、素描、油画、版画等艺术风格。NPR也可以把三维场景渲染出丰富的、特别的新视觉效果,使它具备创新的功能。NPR渲染以强烈的艺术形式应用在动画、游戏等娱乐领域中,也出现在工程、工业设计图纸中。广阔的应用领域,不仅是由于它的艺术表现形式丰富多样,还在于计算机能够辅助完成原本工作量大、难度高的创作工作。 目前,基于三维软件的NPR渲染器相当多,如FinalToon, Il-lustrator, Pencil等,同时还可以借用程序贴图来创建NPR的材质,协助生成手绘风格的图像效果;另外,像Mental Ray,Reyes,Brazil等外挂渲染器都是NPR渲染的解决方案

      引用自【百度百科】

      API

      OpenCV给我们提供了四种非真实渲染的使用场景:边缘保留滤波、细节增强、素描铅笔画、风格化。

      边缘保留滤波

      public static void edgePreservingFilter(Mat src, Mat dst, int flags, float sigma_s, float sigma_r)
      • 参数一:src,输入图像,8位三通道。

      • 参数二:dst,输出图像,8位三通道。

      • 参数三:flags,边缘保留标志位。

      public static final int
              RECURS_FILTER = 1,
              NORMCONV_FILTER = 2;
      • 参数四:sigma_s,邻域大小。取值0~200。

      • 参数五:sigma_r,邻域内被平均的颜色的不相近程度。取值0~1。

      细节增强

      public static void detailEnhance(Mat src, Mat dst, float sigma_s, float sigma_r)
      • 参数一:src,输入图像,8位三通道。

      • 参数二:dst,输出图像,8位三通道。

      • 参数三:sigma_s,邻域大小。取值0~200。

      • 参数四:sigma_r,邻域内被平均的颜色的不相近程度。取值0~1。

      素描铅笔画

      public static void pencilSketch(Mat src, Mat dst1, Mat dst2, float sigma_s, float sigma_r, float shade_factor)
      • 参数一:src,输入图像,8位三通道。

      • 参数二:dst1,输出图像,8位单通道,即黑白素描。

      • 参数三:dst2,输出图像,大小类型与输入图像相同,即彩色素描。

      • 参数四:sigma_s,邻域大小。取值0~200。

      • 参数五:sigma_r,邻域内被平均的颜色的不相近程度。取值0~1。

      • 参数六:shade_factor,强度缩放值。取值0~0.1

      风格化

      public static void stylization(Mat src, Mat dst, float sigma_s, float sigma_r)
      • 参数一:src,输入图像,8位三通道。

      • 参数二:dst,输出图像,8位三通道。

      • 参数三:sigma_s,邻域大小。取值0~200。

      • 参数四:sigma_r,邻域内被平均的颜色的不相近程度。取值0~1。

      关于sigma_s和sigma_r:

      sigma_s,即Sigma_Spatial,决定平滑量。sigma_r,即Sigma_Range,决定平均值。

      典型的平滑滤波器将像素值替换为其相邻像素的加权和。 邻域越大,过滤后的图像看起来越平滑。 邻域的大小与参数sigma_s成正比。但是在边缘保留滤波器里,有两个关键点:1)平滑图片;2)不平滑边缘/颜色边界。换句话说,我们就无法简单地将像素值替换成邻域像素的加权和。而是在邻域内选取和当前像素值相近的像素然后求取平均值,然后替换当前像素值的方式来避免上述问题。所以就需要两个参数来明确范围和颜色相似程度。

      操作

      /**
       * 非真实渲染
       *
       * @author yidong
       * @date 11/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.1f
              set(value) {
                  field = when {
                      value > 1.0f -> {
                          1.0f
                      }
                      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() {
              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() {
              val dst1 = Mat()
              val dst2 = Mat()
              mBinding.isLoading = true
              GlobalScope.launch(Dispatchers.IO) {
                  Photo.pencilSketch(mRgb, dst1, dst2, sigmaR, sigmaS, 0.03f)
                  launch(Dispatchers.Main) {
                      mBinding.isLoading = false
                      mBinding.ivResult.showMat(dst2)
                  }
              }
          }
      
          private fun doStylization() {
              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.0f)
              if (this.sigmaR > 200.0f) {
                  this.sigmaR = 200f
              }
          }
      
          fun decSigmaR(view: View) {
              this.sigmaR = this.sigmaR.minus(1.0f)
              if (this.sigmaR < 0f) {
                  this.sigmaR = 0f
              }
          }
      
          fun incSigmaS(view: View) {
              this.sigmaS = this.sigmaS.plus(.1f)
              if (this.sigmaS > 1.0f) {
                  this.sigmaS = 1f
              }
          }
      
          fun decSigmaS(view: View) {
              this.sigmaS = this.sigmaS.minus(.1f)
              if (this.sigmaS < 0f) {
                  this.sigmaS = 0f
              }
          }
      }

      效果

      感谢各位的阅读,以上就是“Android用OpenCV实现非真实渲染的方法”的内容了,经过本文的学习后,相信大家对Android用OpenCV实现非真实渲染的方法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是天达云,小编将为大家推送更多相关知识点的文章,欢迎关注!

      返回开发技术教程...