AndroidOpenCV(四十六):非真實渲染
非真實渲染
非真實感渲染(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
}
}
}
效果
原始碼
相關文章
- 真實感皮膚渲染技術總結
- 剖析Unreal Engine超真實人類的渲染技術Part 2 - 眼球渲染Unreal
- iPhone 7概念渲染圖曝光 最接近真實的版本iPhone
- GPU精粹與Shader程式設計(四):真實感渲染GPU程式設計
- 剖析Unreal Engine超真實人類的渲染技術Part 3 - 毛髮渲染及其它Unreal
- 不再是渲染圖 微軟Lumia 850真機曝光微軟
- Google Android 真機展示視訊,非全鍵盤GoAndroid
- 什麼是實時渲染,實時渲染是如何工作的
- 基於LOD的大規模真實感室外場景實時渲染技術的初步研究 PART I (轉)
- 鮮花:真實
- 真 · 逃避現實
- 聊聊Canvas渲染相關 (非API層,偏框架設計方面)CanvasAPI框架
- 非真,亦非假——20世紀數學悖論入侵機器學習機器學習
- Salesforce LWC學習(四十六) 自定義Datatable實現cell onclick功能Salesforce
- 預渲染與實時渲染:有什麼區別?
- 實時渲染和預渲染有什麼區別
- Flutter 2 渲染原理和如何實現視訊渲染Flutter
- 史上最真實的VR遊戲,是如何構建“真實”的VR遊戲
- kubernetes實踐之四十六:分散式負載測試Locust分散式負載
- 什麼是實時渲染,3D實時渲染的優缺點3D
- 無論真實還是AI影片,「摩斯卡」都能重建恢復4D動態可渲染場景AI
- OpenGL實現GPU體渲染GPU
- 計算表資料真實行長度獲得表真實大小
- OpenGL/OpenGL ES入門: 影象渲染實現以及渲染問題
- 真實場景再現
- 獲取真實IP地址
- SQL調優真實案例SQL
- 【徵文】真實的DBA工作
- 關於真實和真心
- 達芬奇密碼 第四十六章密碼
- 實現SSR服務端渲染服務端
- 實時渲染:KeyShot Pro for macMac
- 教你實現GPUImage【OpenGL渲染原理】GPUUI
- AI之道|諾獎對AI的偏愛是真魔幻【悟空非空也】AI
- 讓遊戲世界更加真實可信遊戲
- 真實模式和保護模式模式
- Android面試題---真實分享Android面試題
- 優酷真實視訊地址解析