diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index cc661863..ca567fc0 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -12,7 +12,7 @@
-
+
diff --git a/OpenNSFW/src/main/assets/nsfw.tflite b/OpenNSFW/src/main/assets/nsfw.tflite
index a13a741b..9583ed20 100644
Binary files a/OpenNSFW/src/main/assets/nsfw.tflite and b/OpenNSFW/src/main/assets/nsfw.tflite differ
diff --git a/OpenNSFW/src/main/java/com/zwy/opennsfw/core/Classifier.kt b/OpenNSFW/src/main/java/com/zwy/opennsfw/core/Classifier.kt
index 0b43a737..1a80bb94 100644
--- a/OpenNSFW/src/main/java/com/zwy/opennsfw/core/Classifier.kt
+++ b/OpenNSFW/src/main/java/com/zwy/opennsfw/core/Classifier.kt
@@ -6,9 +6,11 @@ import android.graphics.Bitmap
import android.graphics.Color
import android.os.SystemClock
import d
+import e
import mClassifier
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.gpu.GpuDelegate
+import java.io.ByteArrayOutputStream
import java.io.FileInputStream
import java.lang.Math.max
import java.nio.ByteBuffer
@@ -16,6 +18,7 @@ import java.nio.ByteOrder
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
+
class Classifier private constructor(config: Config) {
/**
@@ -52,12 +55,12 @@ class Classifier private constructor(config: Config) {
/**
* Tensorflow Lite
*/
- private lateinit var tflite: Interpreter
+ private var tflite: Interpreter
/**
* 喂入模型的最终数据源
*/
- private lateinit var imgData: ByteBuffer
+ private var imgData: ByteBuffer
companion object {
private var config = Config(context = null)
@@ -104,11 +107,14 @@ class Classifier private constructor(config: Config) {
}
init {
-
- val tfliteOptions = Interpreter.Options()
- if (config.isOpenGPU) tfliteOptions.addDelegate(GpuDelegate())
- tfliteOptions.setNumThreads(config.numThreads)
- tflite = Interpreter(loadModelFile(config.context!!), tfliteOptions)
+ try {
+ tflite =
+ Interpreter(loadModelFile(config.context!!), getTfLiteOptions(config.isOpenGPU))
+ if (config.isOpenGPU) "开启GPU加速成功".d()
+ } catch (e: Exception) {
+ "不支持GPU加速".e()
+ tflite = Interpreter(loadModelFile(config.context!!), getTfLiteOptions(false))
+ }
imgData = ByteBuffer.allocateDirect(
DIM_BATCH_SIZE
@@ -121,6 +127,15 @@ class Classifier private constructor(config: Config) {
imgData.order(ByteOrder.LITTLE_ENDIAN)
}
+ private fun getTfLiteOptions(isOpenGPU: Boolean = true): Interpreter.Options {
+ return Interpreter.Options().apply {
+ if (isOpenGPU) this.addDelegate(GpuDelegate())
+ this.setNumThreads(config.numThreads)
+ this.setAllowBufferHandleOutput(true)
+ this.setAllowFp16PrecisionForFp32(true)
+ }
+ }
+
private fun loadModelFile(context: Context): MappedByteBuffer {
val fileDescriptor = context.assets.openFd("nsfw.tflite")
val inputStream = FileInputStream(fileDescriptor.fileDescriptor)
@@ -160,12 +175,28 @@ class Classifier private constructor(config: Config) {
"数据装载成功,耗时:${(endTime - startTime)} ms".d()
}
+ // # 根据路径获取图片 Image.open(path)
+// # 判断图片的像素格式是否为RGB,如果不是RGB则转换为RGB(24位彩色图像,每个像素用24个bit表示,分别表示红色、绿色和蓝色三个通道)
+// # 重制图片大小为256*256并使用 官方解释:若要调整大小,请对所有可能影响输出值的像素使用线性插值计算输出像素值。对于其他变换,使用输入图像中2x2环境上的线性插值。
+// # 对resize的结果转换为io流并保存为JPEG格式
+// # Convert to 64-bit floating point.asType float32 定义变量存储转换后的32位float图片数据
+// # 获取图片的宽高,截取 224*224大小 x从16位开始,取到16+224位置 y亦是如此
+// # 将取的数值转换位float32
+// # 将每一个颜色值*255
+// # 将每一个颜色减去一定的阈值 104....
+// # [[[127.64.-18]]] 转换为 [[[[127.64.-18]]]]
+// # 使用index关键字喂入模型
+// # 删除所有单维度的条目
+// # 输出扫描结果
fun run(bitmap: Bitmap): NsfwBean {
-
+ //缩放位图时是否应使用双线性过滤。如果这是正确的,则在缩放时将使用双线性滤波,从而以较差的性能为代价具有更好的图像质量。如果这是错误的,则使用最近邻居缩放,这将使图像质量较差但速度更快。推荐的默认设置是将滤镜设置为“ true”,因为双线性滤镜的成本通常很小,并且改善的图像质量非常重要
+ val stream = ByteArrayOutputStream()
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)
+ stream.close()
val bitmap_256 = Bitmap.createScaledBitmap(bitmap, 256, 256, true)
convertBitmapToByteBuffer(bitmap_256)
-
+//
val startTime = SystemClock.uptimeMillis()
// out
val outArray = Array(1) { FloatArray(2) }
@@ -173,8 +204,26 @@ class Classifier private constructor(config: Config) {
tflite.run(imgData, outArray)
val endTime = SystemClock.uptimeMillis()
+ val nsfw = NsfwBean(outArray[0][0], outArray[0][1])
+ "扫描完成[${nsfw}]耗时: ${(endTime - startTime)} ms".d()
+ return nsfw
+ }
- "扫描完成,耗时: ${(endTime - startTime)} ms".d()
- return NsfwBean(outArray[0][0], outArray[0][1])
+ fun bitmap2RGB(bitmap: Bitmap): ByteArray? {
+ val bytes = bitmap.byteCount //返回可用于储存此位图像素的最小字节数
+ val buffer =
+ ByteBuffer.allocate(bytes) // 使用allocate()静态方法创建字节缓冲区
+ bitmap.copyPixelsToBuffer(buffer) // 将位图的像素复制到指定的缓冲区
+ val rgba = buffer.array()
+ val pixels = ByteArray(rgba.size / 4 * 3)
+ val count = rgba.size / 4
+
+ //Bitmap像素点的色彩通道排列顺序是RGBA
+ for (i in 0 until count) {
+ pixels[i * 3] = rgba[i * 4] //R
+ pixels[i * 3 + 1] = rgba[i * 4 + 1] //G
+ pixels[i * 3 + 2] = rgba[i * 4 + 2] //B
+ }
+ return pixels
}
}
\ No newline at end of file
diff --git a/OpenNSFW/src/main/java/com/zwy/opennsfw/utils/kt.kt b/OpenNSFW/src/main/java/com/zwy/opennsfw/utils/kt.kt
index 295639f5..c08e3ee3 100644
--- a/OpenNSFW/src/main/java/com/zwy/opennsfw/utils/kt.kt
+++ b/OpenNSFW/src/main/java/com/zwy/opennsfw/utils/kt.kt
@@ -18,7 +18,8 @@ class NsfwBean(val sfw: Float, val nsfw: Float) {
override fun toString(): String {
val floatFormat = DecimalFormat("0.0000")
floatFormat.roundingMode = RoundingMode.HALF_UP
- return "适宜度(非色情程度):${floatFormat.format(sfw * 100)}%,不适宜度(涉黄程度):${floatFormat.format(nsfw * 100)}%"
+// return "适宜度(非色情程度):${floatFormat.format(sfw * 100)}%,不适宜度(涉黄程度):${floatFormat.format(nsfw * 100)}%"
+ return "sfw:$sfw,nsfw:$nsfw%"
}
}
diff --git a/demo/build.gradle b/demo/build.gradle
index 0842a86c..02d92dfb 100644
--- a/demo/build.gradle
+++ b/demo/build.gradle
@@ -83,7 +83,8 @@ dependencies {
implementation "org.jetbrains.anko:anko:0.10.5"
//NSFW鉴黄库
- implementation 'com.github.devzwy:open_nsfw_android:1.3.0'
+// implementation 'com.github.devzwy:open_nsfw_android:1.3.0'
+ implementation project(path: ':OpenNSFW')
implementation 'pub.devrel:easypermissions:3.0.0'
implementation 'com.github.LuckSiege.PictureSelector:picture_library:2.2.5'
diff --git a/demo/src/main/assets/img/58167612-e474c880-7cbe-11e9-8f33-fdce7e23ffcc.png b/demo/src/main/assets/img/58167612-e474c880-7cbe-11e9-8f33-fdce7e23ffcc.png
new file mode 100644
index 00000000..fcc81787
Binary files /dev/null and b/demo/src/main/assets/img/58167612-e474c880-7cbe-11e9-8f33-fdce7e23ffcc.png differ
diff --git a/demo/src/main/assets/img/test_img1.jpeg b/demo/src/main/assets/img/test_img1.jpeg
deleted file mode 100644
index 2503c3c2..00000000
Binary files a/demo/src/main/assets/img/test_img1.jpeg and /dev/null differ
diff --git a/demo/src/main/assets/img/截屏2020-06-09 10.17.56.png b/demo/src/main/assets/img/截屏2020-06-09 10.17.56.png
new file mode 100644
index 00000000..9aef392f
Binary files /dev/null and b/demo/src/main/assets/img/截屏2020-06-09 10.17.56.png differ
diff --git a/demo/src/main/java/com/zwy/demo/NSFWApplication.kt b/demo/src/main/java/com/zwy/demo/NSFWApplication.kt
index c19460d4..4cbd0deb 100644
--- a/demo/src/main/java/com/zwy/demo/NSFWApplication.kt
+++ b/demo/src/main/java/com/zwy/demo/NSFWApplication.kt
@@ -28,8 +28,8 @@ class NSFWApplication : MultiDexApplication() {
//初始化鉴黄库NSFW
Classifier.Build()
.context(this) //必须调用 否则会有异常抛出
-// .isOpenGPU(true)//默认不开启GPU加速 部分机型开启会奔溃,自行选择,默认false
-// .numThreads(1) //分配的线程数 根据手机配置设置,默认1
+ .isOpenGPU(true)//默认不开启GPU加速 部分机型开启会奔溃,自行选择,默认false
+ .numThreads(100) //分配的线程数 根据手机配置设置,默认1
.build()
//全局注入对象
startKoin {
diff --git a/gradle.properties b/gradle.properties
index 3f8f6b56..aa410575 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,5 @@
org.gradle.jvmargs=-Xmx1536m
kotlin.code.style=official
kotlin.coroutines=enable
-#android.useAndroidX=true
-#android.enableJetifier=true
\ No newline at end of file
+android.useAndroidX=true
+android.enableJetifier=true
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 8709124c..c364d2f2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,3 @@
-//include ':demo' //开启新demo必须注释 include ':app' 并打开gradle.properties中 注释的两行代码 因为新demo使用了androidx与app模块冲突 demo模块完成:Assets目录识别、网络图片识别
-include ':app'
+include ':demo' //开启新demo必须注释 include ':app' 并打开gradle.properties中 注释的两行代码 因为新demo使用了androidx与app模块冲突 demo模块完成:Assets目录识别、网络图片识别
+//include ':app'
include ':OpenNSFW'