Since this application uses * OpenCV * * Mat * (1 row 2D matrix), conversion between * Bitmap * and * Mat * is required. Previously, I told you that I decided to incorporate a process to rotate the image instead of prohibiting the terminal rotation at the screen transition (fragment) process, but there was a problem with the image image mirroring process.
In this application, the image of the gallery or the image taken by the camera is temporarily saved as a file.
If you execute this application with * API 24 / Android 7.0 / Nougat * or above, an exception will occur in * createTempFile * (unique file name) processing.
In * API 24 / Android 7.0 / Nougat * and above, an exception will occur in the processing after * isInvalid () * in * File.createTempFile () *.
Initially, I tried to use * Files.createTempFile () , but the * Files * class is only implemented since * API 26 / Android 8.0 / Oreo * ( Java SE SDK 7 *). We don't care about * createTempFile () * separately, we add absolute time when we instantiate the * File * class to create a unique file name.
Unique file name
// .....Abbreviation
fun getImageFile(context: Context, child: String): File {
context.filesDir.let { path ->
if (!path.exists()) path.mkdir()
return File("$path$child-${System.currentTimeMillis()}$SUFFIX_IMAGE") // $SUFFIX_IMAGE → ".jpg "
}
}
// .....Abbreviation
In this application, after pasting the image image after the screen transition, touch the [Mirror] button on the image image display (processing) screen to perform mirror processing of the image image.
For mirror processing, * Core.flip () * of * OpenCV * is used, but if mirroring is repeated several times, the image will be degraded.
Image image reading → * bitmapToMat (Bitmap → Mat) * → * Core.flip () * → * matToBitmap (Mat → Bitmap) * → When saving an image image * Bitmap * compression format is * JPEG *, lossy compression , Some data will be missing. Normally, the deterioration is so inconspicuous that it is difficult for the human eye to judge, but by repeatedly compressing and saving the image image, the deterioration became noticeable.
Image The image was saved by changing the * Bitmap * compression format to * WEBP * (lossless compression compatible).
Bitmap compression format (WEBP)
// .....Abbreviation
ByteArrayOutputStream().let { outStream ->
bitMap.compress(Bitmap.CompressFormat.WEBP, 100, outStream)
FileOutputStream(argument).apply {
outStream.writeTo(this)
close()
}
}
// .....Abbreviation
In this application, after pasting two image images, touch the [Enter] button on the image image display (processing) screen to perform seamless composition processing of the image images.
In the seamless compositing process, * OpenCV 's * Photo.seamlessClone () * is used, but for compositing (* want to ) original image and compositing ( want to *) destination image and mask If you specify an image, an error ( assertion failed *) will occur.
An error will occur if the size of the original image to be combined () and the image to be combined () are not the same. Also, an error will occur for 4-channel images that include transparency. (Finally noticed in the * OpenCV * source and the * Photo.seamlessClone () * documentation)
Make the size of the original image to be combined (** want to ) and the image to be combined ( want to be **) the same. In addition, each image is specified by 3 channels of 8 bits.
Image conversion of the same size
// .....Abbreviation
private fun createThumbnailBitmap(
bitMap: Bitmap, reqWidth: Int, reqHeight: Int, filter: Boolean
): Bitmap = Bitmap.createScaledBitmap(bitMap, reqWidth, reqHeight, filter)
// .....Abbreviation
Bitmap to Mat conversion
// .....Abbreviation
fun bitmapToMat(bitMap: Bitmap?, colorCode: Int): Mat {
return Mat(bitMap?.height ?: 0, bitMap?.width ?: 0, CvType.CV_8UC3).apply {
Utils.bitmapToMat(bitMap,this, false)
Imgproc.cvtColor(this, this, colorCode, depth())
}
}
// .....Abbreviation
In this application, after pasting two image images, touch the [Enter] button on the image image display (processing) screen to perform seamless composition processing of the image images. After the screen transition, touch the [Save] button on the seamless composition result screen to register the gallery.
Even if the seamlessly composited image is saved in the external area, it is not recognized by * MediaScannerConnection.scanFile () * and is not registered in the gallery.
If you save the seamlessly composited image in the external data area (* Context.getExternalFilesDir () *), it will not be recognized by * MediaScannerConnection.scanFile () *.
By saving the seamlessly composited image in the external public shared area (* Environment.getExternalStoragePublicDirectory () *), it was recognized by * MediaScannerConnection.scanFile () *.
External public shared area storage location
// .....Abbreviation
fun getMixingExternalImageFile(): File {
//The internal data area is not used because the gallery cannot be registered except for the external public shared area.
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
PATH_MIXING_IMAGE // → "SeamlessCollage"
).let { file ->
if (!file.exists()) file.mkdir()
return File("$file$FILE_MIXING_IMAGE-${System.currentTimeMillis()}$SUFFIX_IMAGE")
}
}
// .....Abbreviation
python
// .....Abbreviation
MediaScannerConnection.scanFile(
context,
arrayOf(strUri),
arrayOf("image/jpeg"),
this // MediaScannerConnection.OnScanCompletedListener Callback
)
// .....Abbreviation
Technical causes and countermeasures for the first Android app & Kotlin addiction 1. Android screen transition (fragment) processing 2. Processing related to Android camera function
Recommended Posts