Skip to content

Commit 6f70098

Browse files
committed
SDK v2.5.05
- 新增美型细分参数(眼/鼻/眉/唇): - 眼睛上下、眼高低 - 鼻子大小、鼻子高低、鼻子上下、鼻尖、鼻梁 - 眉粗细、眉长短、眉提升、眉距离、眉倾斜 - 上唇厚度、下唇厚度、丰唇、嘴唇宽度 - 优化多部位链式变形:后续调节基于已变形关键点,修复叠加调节时点位错位问题 - 优化眼部/眉部/唇部多项效果准确性与强度: - 眼距、眼倾斜(旋转)、开眼角 - 眉粗细、眉长短、眉提升、眉倾斜 - 嘴唇上下、上/下唇厚度、丰唇、嘴唇宽度、微笑嘴角 - 优化小头/小脸逻辑:改为基于 bbox 宽高比的椭圆缩放,降低横向过挤压并保持脸型比例 - iOS demo 更新: - 新美型功能与顺序接入 - 新 icon 资源接入(四状态) - 图片处理改为 OpenGL 渲染并修复方向/显示问题 - Android demo 更新: - 新美型功能与 UI 接入,修复参数枚举映射错位 - 美型 icon 资源梳理与补齐(四状态) - 图片处理改为 OpenGL 直渲染,去除 texture->bitmap 回读路径 - C API 文档补充:新增美型枚举注释,包含默认值与调节含义
1 parent dde04df commit 6f70098

1,968 files changed

Lines changed: 99402 additions & 584 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.DS_Store

0 Bytes
Binary file not shown.

SMBeautyEngine_andriod/.DS_Store

2 KB
Binary file not shown.

SMBeautyEngine_andriod/pixelfree_android_demo/.idea/deploymentTargetSelector.xml

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SMBeautyEngine_andriod/pixelfree_android_demo/.idea/gradle.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.hapi.pixelfree_android
2+
3+
import android.content.Context
4+
import android.util.AttributeSet
5+
import android.widget.FrameLayout
6+
7+
class AspectRatioFrameLayout @JvmOverloads constructor(
8+
context: Context,
9+
attrs: AttributeSet? = null,
10+
defStyleAttr: Int = 0
11+
) : FrameLayout(context, attrs, defStyleAttr) {
12+
13+
private var aspectRatio: Float = 1f
14+
15+
init {
16+
attrs?.let {
17+
val typedArray = context.obtainStyledAttributes(it, R.styleable.AspectRatioFrameLayout)
18+
aspectRatio = typedArray.getFloat(R.styleable.AspectRatioFrameLayout_aspectRatio, 1f)
19+
typedArray.recycle()
20+
}
21+
}
22+
23+
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
24+
val width = MeasureSpec.getSize(widthMeasureSpec)
25+
val height = (width / aspectRatio).toInt()
26+
val newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
27+
super.onMeasure(widthMeasureSpec, newHeightMeasureSpec)
28+
}
29+
}
30+
31+

SMBeautyEngine_andriod/pixelfree_android_demo/app/src/main/java/com/hapi/pixelfree_android/ImageActivity.kt

Lines changed: 54 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@ package com.hapi.pixelfree_android
22

33
import android.graphics.Bitmap
44
import android.graphics.BitmapFactory
5-
import android.opengl.GLES20
65
import android.os.Bundle
76
import android.os.Handler
87
import android.os.Looper
98
import android.util.DisplayMetrics
109
import android.util.Log
1110
import android.widget.Button
12-
import android.widget.ImageView
1311
import android.widget.TextView
12+
import android.net.Uri
13+
import androidx.activity.result.contract.ActivityResultContracts
1414
import androidx.appcompat.app.AppCompatActivity
1515
import com.hapi.avparam.ImgFmt
1616
import com.hapi.avparam.VideoFrame
1717
import com.hapi.avrender.HapiCapturePreView
1818
import com.hapi.pixelfree.PFDetectFormat
19+
import com.hapi.pixelfree.PFFaceDetectMode
1920
import com.hapi.pixelfree.PFImageInput
2021
import com.hapi.pixelfree.PFRotationMode
2122
import com.hapi.pixelfree.PFSrcType
2223
import com.hapi.pixelfree.PixelFree
2324
import com.hapi.pixelfreeuikit.PixeBeautyDialog
2425
import com.hapi.pixelfreeuikit.ColorGradingDialog
25-
import java.nio.ByteBuffer
2626

2727
class ImageActivity: AppCompatActivity() {
2828

@@ -41,10 +41,15 @@ class ImageActivity: AppCompatActivity() {
4141

4242
private val handler = Handler(Looper.getMainLooper())
4343
private var frameCount = 0
44-
private lateinit var imageView: ImageView // 声明 ImageView 变量
4544
private lateinit var rgbaData:ByteArray
4645
private lateinit var fpstTextView: TextView
4746

47+
private val pickImageLauncher = registerForActivityResult(
48+
ActivityResultContracts.GetContent()
49+
) { uri: Uri? ->
50+
uri?.let { handleSelectedImage(it) }
51+
}
52+
4853
val hapiCapturePreView by lazy { findViewById<HapiCapturePreView>(R.id.preview) }
4954

5055
var w = 0
@@ -70,9 +75,15 @@ class ImageActivity: AppCompatActivity() {
7075
// 启动定时任务
7176
handler.postDelayed(updateImageRunnable, 1)
7277

73-
// hapiCapturePreView.mHapiGLSurfacePreview.mOpenGLRender.glCreateCall = {
74-
// hapiCapturePreView.setMirror(mirrorHorizontal = true)
78+
// 相册按钮 & 点击预览均可选择相册图片
79+
findViewById<Button>(R.id.btnAlbum).setOnClickListener {
80+
pickImageLauncher.launch("image/*")
81+
}
82+
hapiCapturePreView.setOnClickListener {
83+
pickImageLauncher.launch("image/*")
84+
}
7585

86+
hapiCapturePreView.mHapiGLSurfacePreview.mOpenGLRender.glCreateCall = {
7687
//在绑定上下文后初始化
7788
mPixelFree.create()
7889
val authData = mPixelFree.readBundleFile(this@ImageActivity, "pixelfreeAuth.lic")
@@ -89,8 +100,11 @@ class ImageActivity: AppCompatActivity() {
89100
)
90101
}
91102

103+
// 设置图片检测模式
104+
// mPixelFree.setDetectMode(PFFaceDetectMode.PF_FACE_DETECT_MODE_IMAGE)
105+
92106
mPixeBeautyDialog.show(supportFragmentManager, "")
93-
// }
107+
}
94108

95109
// hapiCapturePreView.setScaleType(ScaleType.FIT_CENTER)
96110
findViewById<Button>(R.id.showBeauty).setOnClickListener {
@@ -139,39 +153,21 @@ class ImageActivity: AppCompatActivity() {
139153
format = PFDetectFormat.PFFORMAT_IMAGE_RGBA
140154
rotationMode = PFRotationMode.PFRotationMode0
141155
}
142-
mPixelFree.processWithBuffer(pxInput)
143-
144-
val frame = pxInput.p_data0?.let {
145-
val out = VideoFrame(
146-
w, h,
147-
ImgFmt.IMAGE_FORMAT_RGBA,
148-
it,
149-
0,
150-
rowBytes,
151-
0,
152-
)
153-
out.textureID = pxInput.textureID
154-
out
156+
if (!isLongPress) {
157+
mPixelFree.processWithBuffer(pxInput)
155158
}
156159

157-
// 截图
158-
// if (frameCount == 100) {
159-
// mPixelFree.glThread.runOnGLThread {
160-
// textureIdToBitmap(pxInput.textureID,pxInput.wigth,pxInput.height);
161-
// }
162-
// }
163-
if (isLongPress) {
164-
displayBitmap(originBitmap)
165-
} else {
166-
mPixelFree.textureIdToBitmap(pxInput.textureID, pxInput.wigth, pxInput.height) { bitmap ->
167-
if (bitmap != null) {
168-
println("[PixelFree] get image bitmap")
169-
displayBitmap(bitmap)
170-
} else {
171-
// Handle error case
172-
}
173-
}
174-
}
160+
val frame = VideoFrame(
161+
w, h,
162+
ImgFmt.IMAGE_FORMAT_RGBA,
163+
rgbaData,
164+
0,
165+
rowBytes,
166+
0,
167+
)
168+
// 长按显示原图;松开显示处理后的 texture
169+
frame.textureID = if (isLongPress) -1000 else pxInput.textureID
170+
hapiCapturePreView.onFrame(frame)
175171

176172
frameCount++
177173
val endTime = System.currentTimeMillis()
@@ -200,23 +196,6 @@ class ImageActivity: AppCompatActivity() {
200196
}
201197
}
202198

203-
private fun displayBitmap(bitmap: Bitmap) {
204-
runOnUiThread { // 确保在主线程更新UI
205-
val imageView = findViewById<ImageView>(R.id.imageView) // 替换为您的ImageView ID
206-
imageView.setImageBitmap(bitmap)
207-
208-
val info = """
209-
🖼️ Bitmap信息:
210-
尺寸: ${bitmap.width}x${bitmap.height}
211-
格式: ${bitmap.config}
212-
内存: ${bitmap.allocationByteCount / 1024} KB
213-
状态: ${if (bitmap.isRecycled) "已回收" else "可用"}
214-
""".trimIndent()
215-
Log.d("BitmapDebug", info);
216-
}
217-
}
218-
219-
220199
private fun convertBitmapToRGBA(bitmap: Bitmap): ByteArray {
221200
val width = bitmap.width
222201
val height = bitmap.height
@@ -226,6 +205,26 @@ class ImageActivity: AppCompatActivity() {
226205
return intArrayToByteArray(rgbaDataa)
227206
}
228207

208+
private fun handleSelectedImage(uri: Uri) {
209+
try {
210+
contentResolver.openInputStream(uri)?.use { input ->
211+
val options = BitmapFactory.Options().apply {
212+
inScaled = false
213+
inDensity = DisplayMetrics.DENSITY_DEFAULT
214+
inTargetDensity = resources.displayMetrics.densityDpi
215+
}
216+
val bitmap = BitmapFactory.decodeStream(input, null, options) ?: return
217+
originBitmap = bitmap
218+
w = bitmap.width
219+
h = bitmap.height
220+
rowBytes = bitmap.rowBytes
221+
rgbaData = convertBitmapToRGBA(bitmap)
222+
}
223+
} catch (e: Exception) {
224+
Log.e("ImageActivity", "Failed to load image from gallery", e)
225+
}
226+
}
227+
229228
private fun applyWhiteningFilter(rgbaData: IntArray, width: Int, height: Int): IntArray {
230229
val whitenedData = IntArray(rgbaData.size)
231230

@@ -300,53 +299,4 @@ class ImageActivity: AppCompatActivity() {
300299
mPixelFree.release()
301300
handler.removeCallbacks(updateImageRunnable) // 停止更新
302301
}
303-
304-
305-
private fun textureIdToBitmap(textureId: Int, width: Int, height: Int): Bitmap? {
306-
GLES20.glFinish();
307-
var mFrameBuffers = IntArray(1)
308-
val mTmpBuffer = ByteBuffer.allocate(width * height * 4)
309-
if (textureId != -1) {
310-
GLES20.glGenFramebuffers(1, mFrameBuffers, 0)
311-
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
312-
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
313-
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[0])
314-
GLES20.glFramebufferTexture2D(
315-
GLES20.GL_FRAMEBUFFER,
316-
GLES20.GL_COLOR_ATTACHMENT0,
317-
GLES20.GL_TEXTURE_2D,
318-
textureId,
319-
0
320-
)
321-
}
322-
GLES20.glReadPixels(
323-
0,
324-
0,
325-
width,
326-
height,
327-
GLES20.GL_RGBA,
328-
GLES20.GL_UNSIGNED_BYTE,
329-
mTmpBuffer
330-
)
331-
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)
332-
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)
333-
334-
// 检查错误
335-
val error = GLES20.glGetError()
336-
if (error != GLES20.GL_NO_ERROR) {
337-
Log.e("OpenGL", "Error reading pixels: $error")
338-
return null
339-
}
340-
341-
// 创建 Bitmap
342-
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
343-
344-
bitmap.copyPixelsFromBuffer(mTmpBuffer)
345-
346-
if (mFrameBuffers != null) {
347-
GLES20.glDeleteFramebuffers(1, mFrameBuffers, 0)
348-
}
349-
return bitmap
350-
}
351-
352302
}

SMBeautyEngine_andriod/pixelfree_android_demo/app/src/main/java/com/hapi/pixelfree_android/MainActivity.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ class MainActivity : AppCompatActivity() {
7272
//在绑定上下文后初始化
7373
mPixelFree.create()
7474
val authData = mPixelFree.readBundleFile(this@MainActivity, "pixelfreeAuth.lic")
75-
authData?.let {
76-
mPixelFree.auth(this.applicationContext, it, it.size)
75+
if (authData != null) {
76+
mPixelFree.auth(this.applicationContext, authData, authData.size)
7777
}
7878
val face_fiter =
7979
mPixelFree.readBundleFile(this@MainActivity, "filter_model.bundle")
80-
face_fiter?.let {
80+
if (face_fiter != null) {
8181
mPixelFree.createBeautyItemFormBundle(
82-
it,
83-
it.size,
82+
face_fiter,
83+
face_fiter.size,
8484
PFSrcType.PFSrcTypeFilter
8585
)
8686
}

SMBeautyEngine_andriod/pixelfree_android_demo/app/src/main/java/com/hapi/pixelfree_android/StartActivity.kt

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import android.content.Intent
55
import android.content.pm.PackageManager
66
import androidx.appcompat.app.AppCompatActivity
77
import android.os.Bundle
8-
import android.widget.Button
98
import androidx.core.app.ActivityCompat
109
import androidx.core.content.ContextCompat
10+
import android.util.Log
1111

1212
class StartActivity : AppCompatActivity() {
1313
companion object {
14-
private const val TAG = "CameraXBasic"
14+
private const val TAG = "StartActivity"
1515
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
1616
private const val REQUEST_CODE_PERMISSIONS = 10
1717
private val REQUIRED_PERMISSIONS = arrayOf(
@@ -28,16 +28,25 @@ class StartActivity : AppCompatActivity() {
2828

2929
override fun onCreate(savedInstanceState: Bundle?) {
3030
super.onCreate(savedInstanceState)
31+
supportActionBar?.hide()
3132
setContentView(R.layout.activity_start)
32-
allPermissionsGranted()
33-
ActivityCompat.requestPermissions(
34-
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
35-
)
36-
findViewById<Button>(R.id.record).setOnClickListener {
33+
34+
// Request permissions
35+
if (!allPermissionsGranted()) {
36+
ActivityCompat.requestPermissions(
37+
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
38+
)
39+
}
40+
41+
// Camera Button
42+
findViewById<androidx.constraintlayout.widget.ConstraintLayout>(R.id.cameraButton).setOnClickListener {
43+
Log.d(TAG, "打开相机预览")
3744
startActivity(Intent(this, MainActivity::class.java))
3845
}
3946

40-
findViewById<Button>(R.id.image).setOnClickListener {
47+
// Image Button
48+
findViewById<androidx.constraintlayout.widget.ConstraintLayout>(R.id.imageButton).setOnClickListener {
49+
Log.d(TAG, "打开图片处理")
4150
startActivity(Intent(this, ImageActivity::class.java))
4251
}
4352
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<shape xmlns:android="http://schemas.android.com/apk/res/android">
3+
<solid android:color="@color/system_background" />
4+
</shape>
5+

0 commit comments

Comments
 (0)