Skip to content

Commit

Permalink
[optimize]风格转移支持输出原内容图像尺寸的风格图了;优化风格转移布局
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Sep 21, 2023
1 parent 803c1a0 commit 75b8113
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,27 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.Button
import androidx.compose.material.icons.filled.Transform
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
Expand All @@ -38,7 +40,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.skyd.rays.R
import com.skyd.rays.base.LoadUiIntent
import com.skyd.rays.ext.showSnackbar
import com.skyd.rays.ui.component.RaysCard
import com.skyd.rays.ui.component.RaysFloatingActionButton
import com.skyd.rays.ui.component.RaysImage
import com.skyd.rays.ui.component.RaysTopBar
import com.skyd.rays.ui.component.dialog.WaitingDialog
Expand All @@ -49,11 +53,47 @@ const val STYLE_TRANSFER_SCREEN_ROUTE = "styleTransferScreen"

@Composable
fun StyleTransferScreen(viewModel: StyleTransferViewModel = hiltViewModel()) {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val context = LocalContext.current
var openWaitingDialog by remember { mutableStateOf(false) }
val uiState by viewModel.uiStateFlow.collectAsStateWithLifecycle()
val loadUiIntentFlow by viewModel.loadUiIntentFlow.collectAsStateWithLifecycle(initialValue = null)
var styleUri by rememberSaveable { mutableStateOf<Uri?>(null) }
var contentUri by rememberSaveable { mutableStateOf<Uri?>(null) }
val pickStyleLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { if (it != null) styleUri = it }
val pickContentLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { if (it != null) contentUri = it }

Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
floatingActionButton = {
RaysFloatingActionButton(
onClick = {
val style = styleUri
val content = contentUri
if (style == null || content == null) {
snackbarHostState.showSnackbar(
scope = scope,
message = context.getString(R.string.style_transfer_screen_image_not_selected)
)
return@RaysFloatingActionButton
}
viewModel.sendUiIntent(
StyleTransferIntent.Transfer(
style = style,
content = content,
)
)
},
contentDescription = stringResource(R.string.style_transfer_screen_transfer),
) {
Icon(imageVector = Icons.Default.Transform, contentDescription = null)
}
},
topBar = {
RaysTopBar(
title = { Text(text = stringResource(id = R.string.style_transfer_screen_name)) },
Expand All @@ -67,7 +107,12 @@ fun StyleTransferScreen(viewModel: StyleTransferViewModel = hiltViewModel()) {
.padding(paddingValues)
.verticalScroll(rememberScrollState())
) {
InputArea()
InputArea(
styleUri = styleUri,
contentUri = contentUri,
onSelectStyleImage = { pickStyleLauncher.launch("image/*") },
onSelectContentImage = { pickContentLauncher.launch("image/*") },
)
val styleTransferResultUiState = uiState.styleTransferResultUiState
if (styleTransferResultUiState is StyleTransferResultUiState.Success) {
ResultArea(bitmap = styleTransferResultUiState.image)
Expand All @@ -79,7 +124,12 @@ fun StyleTransferScreen(viewModel: StyleTransferViewModel = hiltViewModel()) {
.padding(paddingValues)
.verticalScroll(rememberScrollState())
) {
InputArea()
InputArea(
styleUri = styleUri,
contentUri = contentUri,
onSelectStyleImage = { pickStyleLauncher.launch("image/*") },
onSelectContentImage = { pickContentLauncher.launch("image/*") },
)
val styleTransferResultUiState = uiState.styleTransferResultUiState
if (styleTransferResultUiState is StyleTransferResultUiState.Success) {
ResultArea(bitmap = styleTransferResultUiState.image)
Expand Down Expand Up @@ -118,64 +168,57 @@ private fun ResultArea(bitmap: Bitmap) {
}

@Composable
private fun InputArea(viewModel: StyleTransferViewModel = hiltViewModel()) {
var styleUri by rememberSaveable { mutableStateOf<Uri?>(null) }
var contentUri by rememberSaveable { mutableStateOf<Uri?>(null) }
val pickStyleLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { if (it != null) styleUri = it }
val pickContentLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { if (it != null) contentUri = it }
private fun InputArea(
styleUri: Uri?,
contentUri: Uri?,
onSelectStyleImage: () -> Unit,
onSelectContentImage: () -> Unit,
) {
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
.fillMaxWidth(
if (LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact) 1f
else 0.5f
),
horizontalAlignment = Alignment.End,
) {
Row(verticalAlignment = Alignment.CenterVertically) {
RaysCard(modifier = Modifier
.weight(0.5f)
.aspectRatio(1f),
onClick = { pickStyleLauncher.launch("image/*") }
) {
RaysCard(modifier = Modifier.weight(0.5f), onClick = onSelectStyleImage) {
RaysImage(
model = styleUri,
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 120.dp),
contentDescription = null,
contentScale = ContentScale.Crop,
)
Text(
modifier = Modifier
.padding(6.dp)
.align(Alignment.CenterHorizontally),
text = stringResource(R.string.style_transfer_screen_style)
)
}
Spacer(modifier = Modifier.width(10.dp))
Icon(imageVector = Icons.Default.Add, contentDescription = null)
Spacer(modifier = Modifier.width(10.dp))
RaysCard(
modifier = Modifier
.weight(0.5f)
.aspectRatio(1f),
onClick = { pickContentLauncher.launch("image/*") }
) {
RaysCard(modifier = Modifier.weight(0.5f), onClick = onSelectContentImage) {
RaysImage(
model = contentUri,
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 120.dp),
contentDescription = null,
contentScale = ContentScale.Crop,
)
}
}
Spacer(modifier = Modifier.height(10.dp))
Button(
enabled = styleUri != null && contentUri != null,
onClick = {
viewModel.sendUiIntent(
StyleTransferIntent.Transfer(
style = styleUri!!,
content = contentUri!!,
)
Text(
modifier = Modifier
.padding(6.dp)
.align(Alignment.CenterHorizontally),
text = stringResource(R.string.style_transfer_screen_content)
)
}
) {
Text(text = stringResource(R.string.style_transfer_screen_transfer))
}
}
}
28 changes: 19 additions & 9 deletions app/src/main/java/com/skyd/rays/util/StyleTransferUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ import org.tensorflow.lite.support.common.ops.NormalizeOp
import org.tensorflow.lite.support.image.ImageProcessor
import org.tensorflow.lite.support.image.TensorImage
import org.tensorflow.lite.support.image.ops.ResizeOp
import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer
import java.lang.Integer.min

class StyleTransferUtil(
private var numThreads: Int = 2,
Expand Down Expand Up @@ -118,7 +116,11 @@ class StyleTransferUtil(
interpreterTransform?.runForMultipleInputsOutputs(
transformInput, mapOf(Pair(0, outputImage.buffer))
)
val outputBitmap = getOutputImage(outputImage)
val outputBitmap = getOutputImage(
output = outputImage,
outputHeight = image.height,
outputWidth = image.width
)
return outputBitmap to SystemClock.uptimeMillis() - inferenceTime
}

Expand All @@ -138,11 +140,7 @@ class StyleTransferUtil(
targetWidth: Int,
targetHeight: Int
): TensorImage {
val height = image.height
val width = image.width
val cropSize = min(height, width)
val imageProcessor = ImageProcessor.Builder()
.add(ResizeWithCropOrPadOp(cropSize, cropSize))
.add(
ResizeOp(
targetHeight,
Expand All @@ -158,9 +156,21 @@ class StyleTransferUtil(
}

// Convert output bytebuffer to bitmap image.
private fun getOutputImage(output: TensorBuffer): Bitmap {
private fun getOutputImage(
output: TensorBuffer,
outputHeight: Int,
outputWidth: Int,
): Bitmap {
val imagePostProcessor = ImageProcessor.Builder()
.add(DequantizeOp(0f, 255f)).build()
.add(DequantizeOp(0f, 255f))
.add(
ResizeOp(
outputHeight,
outputWidth,
ResizeOp.ResizeMethod.BILINEAR
)
)
.build()
val tensorImage = TensorImage(DataType.FLOAT32)
tensorImage.load(output)
return imagePostProcessor.process(tensorImage).bitmap
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@
<string name="mini_tool_screen_name">小工具</string>
<string name="style_transfer_screen_name">风格转移(实验性)</string>
<string name="style_transfer_screen_transfer">转移</string>
<string name="style_transfer_screen_image_not_selected">请选择目标风格图片和内容图片后再进行转换</string>
<string name="style_transfer_screen_style">风格</string>
<string name="style_transfer_screen_content">内容</string>
<string name="api_screen_name">API(实验性)</string>
<string name="api_grant_screen_name">API 授权</string>
<string name="setting_screen_api_description">对外开放接口</string>
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@
<string name="mini_tool_screen_name">Mini Tool</string>
<string name="style_transfer_screen_name">Style Transfer (Experimental)</string>
<string name="style_transfer_screen_transfer">Transfer</string>
<string name="style_transfer_screen_image_not_selected">Please select the target style image and content image before transferring</string>
<string name="style_transfer_screen_style">Style</string>
<string name="style_transfer_screen_content">Content</string>
<string name="api_screen_name">API (Experimental)</string>
<string name="api_grant_screen_name">API Grant</string>
<string name="setting_screen_api_description">Application Programming Interface</string>
Expand Down

0 comments on commit 75b8113

Please sign in to comment.