Skip to content

Instantly share code, notes, and snippets.

@LiewJunTung
Created July 13, 2019 18:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save LiewJunTung/b9b7f8444037fbcbe5b30a915850d494 to your computer and use it in GitHub Desktop.
Save LiewJunTung/b9b7f8444037fbcbe5b30a915850d494 to your computer and use it in GitHub Desktop.
Best solution YUV -> RGB
class RgbConversion(val rs: RenderScript, private val feedSize: Size, private val hasRotate: Boolean = true) {
private var mInputAllocation: Allocation? = null
private var mOutputAllocation: Allocation? = null
private var mRotatedAllocation: Allocation? = null
private val yuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))
private val rotator = ScriptC_rotator(rs)
var bufferCallback: ((ByteBuffer) -> Unit)? = null
val inputSurface: Surface
get() = mInputAllocation!!.surface
private val onBufferAvailable = Allocation.OnBufferAvailableListener {
it.ioReceive()
yuvToRgb.setInput(it)
yuvToRgb.forEach(mOutputAllocation)
if (hasRotate) {
rotator._inImage = mOutputAllocation
rotator._inWidth = feedSize.width
rotator._inHeight = feedSize.height
rotator.forEach_rotate_270_clockwise_natural(mRotatedAllocation, mRotatedAllocation)
bufferCallback?.invoke(mRotatedAllocation!!.byteBuffer)
} else {
bufferCallback?.invoke(mOutputAllocation!!.byteBuffer)
}
}
init {
createAllocations(rs)
mInputAllocation!!.setOnBufferAvailableListener(onBufferAvailable)
}
private fun createAllocations(rs: RenderScript) {
val width = feedSize.width
val height = feedSize.height
println("Allocation $width, $height")
val yuvType = Type.Builder(rs, Element.U8_4(rs))
.setX(width)
.setY(height)
.setYuvFormat(ImageFormat.YUV_420_888)
.create()
mInputAllocation = Allocation.createTyped(
rs, yuvType,
Allocation.USAGE_IO_INPUT or Allocation.USAGE_SCRIPT
)
val rgbType = Type.createXY(rs, Element.RGBA_8888(rs), width, height)
mOutputAllocation = Allocation.createTyped(
rs, rgbType, Allocation.USAGE_SCRIPT
)
val rotated = Type.createXY(rs, Element.RGBA_8888(rs), height, width)
mRotatedAllocation = Allocation.createTyped(
rs, rotated, Allocation.USAGE_SCRIPT
)
}
}
class YuvToRgbActivity : AppCompatActivity() {
private val aspectRatio: Rational = Rational(16, 9)
private lateinit var renderScript: RenderScript
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
renderScript = RenderScript.create(this)
setContentView(R.layout.activity_yuv_to_rgb)
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}
}
private fun startCamera() {
CameraX.bindToLifecycle(this, imageAnalysisSetup(), imageCaptureSetup())
}
fun setupPreview(): Preview {
val previewConfig = PreviewConfig.Builder()
.setLensFacing(CameraX.LensFacing.FRONT)
.build()
return Preview(previewConfig)
}
fun imageCaptureSetup(): ImageCapture {
val width = 3264
val height = 2448
val captureConfig = ImageCaptureConfig.Builder()
.setLensFacing(CameraX.LensFacing.FRONT)
.setBufferFormat(ImageFormat.YUV_420_888)
.setTargetResolution(Size(width, height))
.build()
val mConversionScript = RgbConversion(RenderScript.create(this), Size(width, height))
val imagewriter = ImageWriter.newInstance(mConversionScript.inputSurface, 1)
mConversionScript.bufferCallback = { rgbBuffer ->
Log.d("CAPTURED!!", rgbBuffer.capacity().toString())
val bitmapImage = Bitmap.createBitmap(height, width, Bitmap.Config.ARGB_8888)
caturedView.post {
rgbBuffer.rewind()
bitmapImage.copyPixelsFromBuffer(rgbBuffer)
caturedView.setImageBitmap(bitmapImage)
}
}
val imageCapture = ImageCapture(captureConfig)
button.setOnClickListener {
imageCapture.takePicture(object : ImageCapture.OnImageCapturedListener() {
override fun onCaptureSuccess(image: ImageProxy, rotationDegrees: Int) {
Log.d("TTA", "${image.width} ${image.height}")
imagewriter.queueInputImage(image.image)
image.close()
}
})
}
return imageCapture
}
fun imageAnalysisSetup(): ImageAnalysis {
val width = 1920
val height = 1080
//val imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 1)
val imageReadConfig = ImageAnalysisConfig.Builder().apply {
// Use a worker thread for image analysis to prevent glitches
setLensFacing((CameraX.LensFacing.FRONT))
setTargetAspectRatio(aspectRatio)
setTargetResolution(Size(width, height))
val analyzerThread = HandlerThread("Analyser").apply { start() }
setCallbackHandler(Handler(analyzerThread.looper))
setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
}
val mConversionScript = RgbConversion(renderScript, Size(width, height))
val imagewriter = ImageWriter.newInstance(mConversionScript.inputSurface, 1)
val bitmapImage = Bitmap.createBitmap(height, width, Bitmap.Config.ARGB_8888)
mConversionScript.bufferCallback = { rgbBuffer ->
Log.d("BUFFER!!", rgbBuffer.capacity().toString())
previewView.post {
rgbBuffer.rewind()
bitmapImage.copyPixelsFromBuffer(rgbBuffer)
previewView.setImageBitmap(bitmapImage)
}
}
return ImageAnalysis(imageReadConfig.build()).apply {
analyzer = ImageAnalysis.Analyzer { image, rotationDegrees ->
imagewriter.queueInputImage(image.image)
}
}
}
/**
* Check if all permission specified in the manifest have been granted
*/
private fun allPermissionsGranted(): Boolean {
for (permission in REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false
}
}
return true
}
/**
* Process result from permission request dialog box, has the request
* been granted? If yes, start Camera. Otherwise display a toast
*/
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray
) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
caturedView.post { startCamera() }
} else {
Toast.makeText(
this,
"Permissions not granted by the user.",
Toast.LENGTH_SHORT
).show()
finish()
}
}
}
}
@matteo411
Copy link

imagewriter.queueInputImage(image.image)
is throwing a java.lang.IllegalStateException: Image is already closed

@matteo411
Copy link

I've found that it works if you change the ImageReader mode from ACQUIRE_LATEST_IMAGE to ACQUIRE_NEXT_IMAGE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment