parent
							
								
									0123fd9243
								
							
						
					
					
						commit
						de513b60e3
					
				| @ -1,8 +1,5 @@ | ||||
| package com.example.open_nsfw_android | ||||
| 
 | ||||
| import android.graphics.Bitmap | ||||
| import com.zwy.nsfw.api.NsfwBean | ||||
| 
 | ||||
| data class MyNsfwBean(var sfw: Float,var nsfw: Float, val path: String,val bitmap:Bitmap) { | ||||
| 
 | ||||
| } | ||||
| data class MyNsfwBean(var sfw: Float, var nsfw: Float, val path: String, val bitmap: Bitmap) | ||||
| @ -1,210 +0,0 @@ | ||||
| 
 | ||||
| package com.zwy.nsfw; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.content.res.AssetFileDescriptor; | ||||
| import android.graphics.*; | ||||
| import android.os.Environment; | ||||
| import android.os.SystemClock; | ||||
| import android.util.Log; | ||||
| import com.zwy.nsfw.api.NsfwBean; | ||||
| import org.tensorflow.lite.Interpreter; | ||||
| import org.tensorflow.lite.Tensor; | ||||
| import org.tensorflow.lite.gpu.GpuDelegate; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.ByteOrder; | ||||
| import java.nio.MappedByteBuffer; | ||||
| import java.nio.channels.FileChannel; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import static java.lang.Math.max; | ||||
| 
 | ||||
| public class Classifier { | ||||
| 
 | ||||
|     public static final String TAG = "open_nsfw_android"; | ||||
| 
 | ||||
|     /** | ||||
|      * tensor input img size | ||||
|      */ | ||||
|     private final int INPUT_WIDTH = 224; | ||||
|     private final int INPUT_HEIGHT = 224; | ||||
| 
 | ||||
|     /** | ||||
|      * BytesPerChannel | ||||
|      */ | ||||
|     private final int BYTES_PER_CHANNEL_NUM = 4; | ||||
|     /** | ||||
|      * Dimensions of inputs. | ||||
|      */ | ||||
|     private static final int DIM_BATCH_SIZE = 1; | ||||
| 
 | ||||
|     private static final int DIM_PIXEL_SIZE = 3; | ||||
| 
 | ||||
|     /** | ||||
|      * Preallocated buffers for storing image data in. | ||||
|      */ | ||||
|     private int[] intValues = new int[INPUT_WIDTH * INPUT_HEIGHT]; | ||||
|     List<Integer> list = new ArrayList<>(); | ||||
|     /** | ||||
|      * The loaded TensorFlow Lite model. | ||||
|      */ | ||||
|     private MappedByteBuffer tfliteModel; | ||||
| 
 | ||||
|     /** | ||||
|      * Optional GPU delegate for accleration. | ||||
|      */ | ||||
|     private GpuDelegate gpuDelegate = null; | ||||
| 
 | ||||
|     /** | ||||
|      * An instance of the driver class to run model inference with Tensorflow Lite. | ||||
|      */ | ||||
|     private Interpreter tflite; | ||||
| 
 | ||||
|     /** | ||||
|      * A ByteBuffer to hold image data, to be feed into Tensorflow Lite as inputs. | ||||
|      */ | ||||
|     private ByteBuffer imgData; | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a classifier with the provided configuration. | ||||
|      * | ||||
|      * @param activity         The current Activity. | ||||
|      * @param isAddGpuDelegate Add gpu delegate | ||||
|      * @param numThreads       The number of threads to use for classification. | ||||
|      * @return A classifier with the desired configuration. | ||||
|      */ | ||||
|     public static Classifier create(Activity activity, Boolean isAddGpuDelegate, int numThreads) | ||||
|             throws IOException { | ||||
|         return new Classifier(activity, isAddGpuDelegate, numThreads); | ||||
|     } | ||||
| 
 | ||||
|     private Classifier(Activity activity, Boolean isGPU, int numThreads) throws IOException { | ||||
|         tfliteModel = loadModelFile(activity); | ||||
|         Interpreter.Options tfliteOptions = new Interpreter.Options(); | ||||
|         if (isGPU) { | ||||
|             gpuDelegate = new GpuDelegate(); | ||||
|             tfliteOptions.addDelegate(gpuDelegate); | ||||
|         } | ||||
|         tfliteOptions.setNumThreads(numThreads); | ||||
|         tflite = new Interpreter(tfliteModel, tfliteOptions); | ||||
| 
 | ||||
|         Tensor tensor = tflite.getInputTensor(tflite.getInputIndex("input")); | ||||
|         String stringBuilder = " \n" | ||||
|                 + "dataType : " + | ||||
|                 tensor.dataType() + | ||||
|                 "\n" + | ||||
|                 "numBytes : " + | ||||
|                 tensor.numBytes() + | ||||
|                 "\n" + | ||||
|                 "numDimensions : " + | ||||
|                 tensor.numDimensions() + | ||||
|                 "\n" + | ||||
|                 "numElements : " + | ||||
|                 tensor.numElements() + | ||||
|                 "\n" + | ||||
|                 "shape : " + | ||||
|                 tensor.shape().length; | ||||
|         Log.d(TAG, stringBuilder); | ||||
| 
 | ||||
|         imgData = | ||||
|                 ByteBuffer.allocateDirect( | ||||
|                         DIM_BATCH_SIZE | ||||
|                                 * INPUT_WIDTH | ||||
|                                 * INPUT_HEIGHT | ||||
|                                 * DIM_PIXEL_SIZE | ||||
|                                 * BYTES_PER_CHANNEL_NUM); | ||||
| 
 | ||||
|         imgData.order(ByteOrder.LITTLE_ENDIAN); | ||||
|         Log.d(TAG, "Tensorflow Lite Image Classifier Initialization Success."); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Memory-map the model file in Assets. | ||||
|      */ | ||||
|     private MappedByteBuffer loadModelFile(Activity activity) throws IOException { | ||||
|         AssetFileDescriptor fileDescriptor = activity.getAssets().openFd("nsfw.tflite"); | ||||
|         FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor()); | ||||
|         FileChannel fileChannel = inputStream.getChannel(); | ||||
|         long startOffset = fileDescriptor.getStartOffset(); | ||||
|         long declaredLength = fileDescriptor.getDeclaredLength(); | ||||
|         return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Writes Image data into a {@code ByteBuffer}. | ||||
|      */ | ||||
|     private void convertBitmapToByteBuffer(Bitmap bitmap_) { | ||||
|         if (imgData == null || bitmap_ == null) { | ||||
|             return; | ||||
|         } | ||||
|         imgData.rewind(); | ||||
|         int W = bitmap_.getWidth(); | ||||
|         int H = bitmap_.getHeight(); | ||||
| 
 | ||||
|         int w_off = max((W - INPUT_WIDTH) / 2, 0); | ||||
|         int h_off = max((H - INPUT_HEIGHT) / 2, 0); | ||||
| 
 | ||||
|         //把每个像素的颜色值转为int 存入intValues
 | ||||
|         bitmap_.getPixels(intValues, 0, INPUT_WIDTH, h_off, w_off, INPUT_WIDTH, INPUT_HEIGHT); | ||||
|         // Convert the image to floating point.
 | ||||
|         long startTime = SystemClock.uptimeMillis(); | ||||
|         for (final int color : intValues) { | ||||
|             int r1 = Color.red(color); | ||||
|             int g1 = Color.green(color); | ||||
|             int b1 = Color.blue(color); | ||||
| 
 | ||||
|             int rr1 = r1 - 123; | ||||
|             int gg1 = g1 - 117; | ||||
|             int bb1 = b1 - 104; | ||||
| 
 | ||||
|             imgData.putFloat(bb1); | ||||
|             imgData.putFloat(gg1); | ||||
|             imgData.putFloat(rr1); | ||||
|         } | ||||
|         long endTime = SystemClock.uptimeMillis(); | ||||
|         Log.d(TAG, "Timecost to put values into ByteBuffer: " + (endTime - startTime) + "ms"); | ||||
|     } | ||||
| 
 | ||||
|     public NsfwBean run(Bitmap bitmap) { | ||||
| 
 | ||||
|         Bitmap bitmap_256 = Bitmap.createScaledBitmap(bitmap, 256, 256,true); | ||||
| 
 | ||||
|         //Writes image data into byteBuffer
 | ||||
|         convertBitmapToByteBuffer(bitmap_256); | ||||
| 
 | ||||
|         long startTime = SystemClock.uptimeMillis(); | ||||
|         // out
 | ||||
|         float[][] outArray = new float[1][2]; | ||||
| 
 | ||||
|         tflite.run(imgData, outArray); | ||||
| 
 | ||||
|         long endTime = SystemClock.uptimeMillis(); | ||||
| 
 | ||||
|         Log.d(TAG, "SFW score :" + outArray[0][0] + ",NSFW score :" + outArray[0][1]); | ||||
|         Log.d(TAG, "Timecost to run model inference: " + (endTime - startTime) + "ms"); | ||||
|         return new NsfwBean(outArray[0][0], outArray[0][1]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Closes the interpreter and model to release resources. | ||||
|      */ | ||||
|     public void close() { | ||||
|         if (tflite != null) { | ||||
|             tflite.close(); | ||||
|             tflite = null; | ||||
|             Log.d(TAG, "Tensorflow Lite Image Classifier close."); | ||||
|         } | ||||
|         if (gpuDelegate != null) { | ||||
|             gpuDelegate.close(); | ||||
|             Log.d(TAG, "Tensorflow Lite Image gpuDelegate close."); | ||||
|             gpuDelegate = null; | ||||
|         } | ||||
|         tfliteModel = null; | ||||
|         Log.d(TAG, "Tensorflow Lite destroyed."); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,42 @@ | ||||
| package com.zwy.nsfw.api | ||||
| 
 | ||||
| import android.graphics.Bitmap | ||||
| import com.zwy.nsfw.core.Classifier | ||||
| import com.zwy.nsfw.core.NSFWConfig | ||||
| import com.zwy.nsfw.core.NsfwBean | ||||
| 
 | ||||
| object NSFWHelper { | ||||
| 
 | ||||
|     private lateinit var classifier: Classifier | ||||
| 
 | ||||
|     private var isInit = false | ||||
| 
 | ||||
|     @Synchronized | ||||
|     fun init(nsfwConfig: NSFWConfig): NSFWHelper { | ||||
|         classifier = Classifier.create(nsfwConfig.assetMannager, nsfwConfig.userGPU, 10) | ||||
|         isInit = true | ||||
|         return this | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 同步扫描图片(建议使用者自己放在线程中处理) | ||||
|      */ | ||||
|     @Synchronized | ||||
|     fun scanBitmap(bitmap: Bitmap): NsfwBean { | ||||
|         if (!isInit) { | ||||
|             throw ExceptionInInitializerError("Initialize the scanned object 'NSFWHelper.init(nsfwConfig: NSFWConfig)' by calling the function first.") | ||||
|         } | ||||
|         return classifier.run(bitmap) | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 不会销毁该单利和配置的参数,建议页面处理完成后调用该代码对扫描器进行关闭,关闭后下次扫描不需要再次调用init方法 | ||||
|      */ | ||||
|     fun destroyFactory() { | ||||
|         classifier.close() | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| @ -1,27 +0,0 @@ | ||||
| package com.zwy.nsfw.api; | ||||
| 
 | ||||
| public class NsfwBean { | ||||
|     private float sfw; | ||||
|     private float nsfw; | ||||
| 
 | ||||
|     public NsfwBean(float sfw, float nsfw) { | ||||
|         this.sfw = sfw; | ||||
|         this.nsfw = nsfw; | ||||
|     } | ||||
| 
 | ||||
|     public float getSfw() { | ||||
|         return sfw; | ||||
|     } | ||||
| 
 | ||||
|     public float getNsfw() { | ||||
|         return nsfw; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "NsfwBean{" + | ||||
|                 "sfw=" + sfw + | ||||
|                 ", nsfw=" + nsfw + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -1,90 +0,0 @@ | ||||
| package com.zwy.nsfw.api; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.graphics.Bitmap; | ||||
| import android.util.Log; | ||||
| import com.zwy.nsfw.Classifier; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class NsfwHelper { | ||||
|     @SuppressLint("StaticFieldLeak") | ||||
|     private static NsfwHelper nsfwHelper; | ||||
|     private Activity activity; | ||||
|     private Classifier classifier; | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a classifier with the provided configuration. | ||||
|      * | ||||
|      * @param activity         The current Activity. | ||||
|      * @param isAddGpuDelegate Add gpu delegate | ||||
|      * @param numThreads       The number of threads to use for classification. | ||||
|      * @return A classifier with the desired configuration. | ||||
|      */ | ||||
|     public static NsfwHelper getInstance(Activity activity, Boolean isAddGpuDelegate, int numThreads) { | ||||
|         synchronized (NsfwHelper.class) { | ||||
|             if (nsfwHelper == null) { | ||||
|                 nsfwHelper = new NsfwHelper(activity, isAddGpuDelegate, numThreads); | ||||
|             } | ||||
|         } | ||||
|         return nsfwHelper; | ||||
|     } | ||||
| 
 | ||||
|     private NsfwHelper(Activity activity, Boolean isAddGpuDelegate, int numThreads) { | ||||
|         try { | ||||
|             this.activity = activity; | ||||
|             classifier = Classifier.create(activity, isAddGpuDelegate, numThreads); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             Log.e(Classifier.TAG, "Tensorflow Lite Image Classifier Initialization Error,e:" + e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 同步扫描 | ||||
|      * | ||||
|      * @param bitmap | ||||
|      * @return nsfw/sfw | ||||
|      */ | ||||
|     public NsfwBean scanBitmapSyn(Bitmap bitmap) { | ||||
|         synchronized (NsfwHelper.class) { | ||||
|             return classifier.run(bitmap); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 异步扫描 | ||||
|      * | ||||
|      * @param bitmap | ||||
|      * @param onScanBitmapListener void onSuccess(float sfw, float nsfw); | ||||
|      */ | ||||
|     public void scanBitmap(final Bitmap bitmap, final OnScanBitmapListener onScanBitmapListener) { | ||||
|         new Thread(new Runnable() { | ||||
|             @Override | ||||
|             public void run() { | ||||
|                 final NsfwBean nsfwBean = scanBitmapSyn(bitmap); | ||||
|                 activity.runOnUiThread(new Runnable() { | ||||
|                     @Override | ||||
|                     public void run() { | ||||
|                         onScanBitmapListener.onSuccess(nsfwBean.getSfw(), nsfwBean.getNsfw()); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         }).start(); | ||||
|     } | ||||
| 
 | ||||
|     public void destroy() { | ||||
|         classifier.close(); | ||||
|         activity = null; | ||||
|         nsfwHelper = null; | ||||
|     } | ||||
| 
 | ||||
|     public  interface OnScanBitmapListener { | ||||
|         void onSuccess(float sfw, float nsfw); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,197 @@ | ||||
| package com.zwy.nsfw.core | ||||
| 
 | ||||
| import android.content.res.AssetManager | ||||
| import android.graphics.Bitmap | ||||
| import android.graphics.Color | ||||
| import android.os.SystemClock | ||||
| import android.util.Log | ||||
| import org.tensorflow.lite.Interpreter | ||||
| import org.tensorflow.lite.gpu.GpuDelegate | ||||
| import java.io.FileInputStream | ||||
| import java.lang.Math.max | ||||
| import java.nio.ByteBuffer | ||||
| import java.nio.ByteOrder | ||||
| import java.nio.MappedByteBuffer | ||||
| import java.nio.channels.FileChannel | ||||
| 
 | ||||
| class Classifier | ||||
| private constructor(assetManager: AssetManager, isGPU: Boolean?, numThreads: Int) { | ||||
| 
 | ||||
|     /** | ||||
|      * tensor input img size | ||||
|      */ | ||||
|     private val INPUT_WIDTH = 224 | ||||
|     private val INPUT_HEIGHT = 224 | ||||
| 
 | ||||
|     /** | ||||
|      * BytesPerChannel | ||||
|      */ | ||||
|     private val BYTES_PER_CHANNEL_NUM = 4 | ||||
| 
 | ||||
|     /** | ||||
|      * Preallocated buffers for storing image data in. | ||||
|      */ | ||||
|     private val intValues = IntArray(INPUT_WIDTH * INPUT_HEIGHT) | ||||
|     /** | ||||
|      * The loaded TensorFlow Lite model. | ||||
|      */ | ||||
|     private var tfliteModel: MappedByteBuffer? = null | ||||
| 
 | ||||
|     /** | ||||
|      * Optional GPU delegate for accleration. | ||||
|      */ | ||||
|     private var gpuDelegate: GpuDelegate? = null | ||||
| 
 | ||||
|     /** | ||||
|      * An instance of the driver class to run model inference with Tensorflow Lite. | ||||
|      */ | ||||
|     private var tflite: Interpreter? = null | ||||
| 
 | ||||
|     /** | ||||
|      * A ByteBuffer to hold image data, to be feed into Tensorflow Lite as inputs. | ||||
|      */ | ||||
|     private val imgData: ByteBuffer? | ||||
| 
 | ||||
|     init { | ||||
|         tfliteModel = loadModelFile(assetManager) | ||||
|         val tfliteOptions = Interpreter.Options() | ||||
|         if (isGPU == true) { | ||||
|             gpuDelegate = GpuDelegate() | ||||
|             tfliteOptions.addDelegate(gpuDelegate) | ||||
|         } | ||||
|         tfliteOptions.setNumThreads(numThreads) | ||||
|         tflite = Interpreter(tfliteModel!!, tfliteOptions) | ||||
| 
 | ||||
|         val tensor = tflite!!.getInputTensor(tflite!!.getInputIndex("input")) | ||||
|         val stringBuilder = (" \n" | ||||
|                 + "dataType : " + | ||||
|                 tensor.dataType() + | ||||
|                 "\n" + | ||||
|                 "numBytes : " + | ||||
|                 tensor.numBytes() + | ||||
|                 "\n" + | ||||
|                 "numDimensions : " + | ||||
|                 tensor.numDimensions() + | ||||
|                 "\n" + | ||||
|                 "numElements : " + | ||||
|                 tensor.numElements() + | ||||
|                 "\n" + | ||||
|                 "shape : " + | ||||
|                 tensor.shape().size) | ||||
|         Log.d(TAG, stringBuilder) | ||||
| 
 | ||||
|         imgData = ByteBuffer.allocateDirect( | ||||
|             DIM_BATCH_SIZE | ||||
|                     * INPUT_WIDTH | ||||
|                     * INPUT_HEIGHT | ||||
|                     * DIM_PIXEL_SIZE | ||||
|                     * BYTES_PER_CHANNEL_NUM | ||||
|         ) | ||||
| 
 | ||||
|         imgData!!.order(ByteOrder.LITTLE_ENDIAN) | ||||
|         Log.d(TAG, "Tensorflow Lite Image Classifier Initialization Success.") | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Memory-map the model file in Assets. | ||||
|      */ | ||||
|     private fun loadModelFile(assetManager: AssetManager): MappedByteBuffer { | ||||
|         val fileDescriptor = assetManager.openFd("nsfw.tflite") | ||||
|         val inputStream = FileInputStream(fileDescriptor.fileDescriptor) | ||||
|         val fileChannel = inputStream.channel | ||||
|         val startOffset = fileDescriptor.startOffset | ||||
|         val declaredLength = fileDescriptor.declaredLength | ||||
|         return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength) | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Writes Image data into a `ByteBuffer`. | ||||
|      */ | ||||
|     private fun convertBitmapToByteBuffer(bitmap_: Bitmap) { | ||||
|         if (imgData == null || bitmap_ == null) { | ||||
|             return | ||||
|         } | ||||
|         imgData.rewind() | ||||
|         val W = bitmap_.width | ||||
|         val H = bitmap_.height | ||||
| 
 | ||||
|         val w_off = max((W - INPUT_WIDTH) / 2, 0) | ||||
|         val h_off = max((H - INPUT_HEIGHT) / 2, 0) | ||||
| 
 | ||||
|         //把每个像素的颜色值转为int 存入intValues
 | ||||
|         bitmap_.getPixels(intValues, 0, INPUT_WIDTH, h_off, w_off, INPUT_WIDTH, INPUT_HEIGHT) | ||||
|         // Convert the image to floating point.
 | ||||
|         val startTime = SystemClock.uptimeMillis() | ||||
|         for (color in intValues) { | ||||
|             val r1 = Color.red(color) | ||||
|             val g1 = Color.green(color) | ||||
|             val b1 = Color.blue(color) | ||||
| 
 | ||||
|             val rr1 = r1 - 123 | ||||
|             val gg1 = g1 - 117 | ||||
|             val bb1 = b1 - 104 | ||||
| 
 | ||||
|             imgData.putFloat(bb1.toFloat()) | ||||
|             imgData.putFloat(gg1.toFloat()) | ||||
|             imgData.putFloat(rr1.toFloat()) | ||||
|         } | ||||
|         val endTime = SystemClock.uptimeMillis() | ||||
|         Log.d(TAG, "Timecost to put values into ByteBuffer: " + (endTime - startTime) + "ms") | ||||
|     } | ||||
| 
 | ||||
|     fun run(bitmap: Bitmap): NsfwBean { | ||||
| 
 | ||||
|         val bitmap_256 = Bitmap.createScaledBitmap(bitmap, 256, 256, true) | ||||
| 
 | ||||
|         //Writes image data into byteBuffer
 | ||||
|         convertBitmapToByteBuffer(bitmap_256) | ||||
| 
 | ||||
|         val startTime = SystemClock.uptimeMillis() | ||||
|         // out
 | ||||
|         val outArray = Array(1) { FloatArray(2) } | ||||
| 
 | ||||
|         tflite!!.run(imgData, outArray) | ||||
| 
 | ||||
|         val endTime = SystemClock.uptimeMillis() | ||||
| 
 | ||||
|         Log.d(TAG, "SFW score :" + outArray[0][0] + ",NSFW score :" + outArray[0][1]) | ||||
|         Log.d(TAG, "Timecost to run model inference: " + (endTime - startTime) + "ms") | ||||
|         return NsfwBean(outArray[0][0], outArray[0][1]) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Closes the interpreter and model to release resources. | ||||
|      */ | ||||
|     fun close() { | ||||
|         if (tflite != null) { | ||||
|             tflite!!.close() | ||||
|             tflite = null | ||||
|             Log.d(TAG, "Tensorflow Lite Image Classifier close.") | ||||
|         } | ||||
|         if (gpuDelegate != null) { | ||||
|             gpuDelegate!!.close() | ||||
|             Log.d(TAG, "Tensorflow Lite Image gpuDelegate close.") | ||||
|             gpuDelegate = null | ||||
|         } | ||||
|         tfliteModel = null | ||||
|         Log.d(TAG, "Tensorflow Lite destroyed.") | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
| 
 | ||||
|         val TAG = "open_nsfw_android" | ||||
|         /** | ||||
|          * Dimensions of inputs. | ||||
|          */ | ||||
|         private val DIM_BATCH_SIZE = 1 | ||||
| 
 | ||||
|         private val DIM_PIXEL_SIZE = 3 | ||||
| 
 | ||||
|         fun create(assetManager: AssetManager, isAddGpuDelegate: Boolean?, numThreads: Int): Classifier { | ||||
|             return Classifier(assetManager, isAddGpuDelegate!!, numThreads) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,10 @@ | ||||
| package com.zwy.nsfw.core | ||||
| 
 | ||||
| import android.content.res.AssetManager | ||||
| 
 | ||||
| /** | ||||
|  * 配置扫描参数 | ||||
|  * [assetMannager]资源管理器,用于读取lib下的tfLite文件 | ||||
|  * [userGPU]是否开启GPU加速 默认关闭,部分手机开启后会有奔溃 | ||||
|  */ | ||||
| data class NSFWConfig(val assetMannager: AssetManager, val userGPU: Boolean = false) | ||||
| @ -0,0 +1,3 @@ | ||||
| package com.zwy.nsfw.core | ||||
| 
 | ||||
| class NsfwBean(val sfw: Float, val nsfw: Float) | ||||
					Loading…
					
					
				
		Reference in new issue