-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7d620ad
commit 23ce641
Showing
96 changed files
with
1,374 additions
and
2 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
*.iml | ||
.gradle | ||
/local.properties | ||
/.idea/caches | ||
/.idea/libraries | ||
/.idea/modules.xml | ||
/.idea/workspace.xml | ||
/.idea/navEditor.xml | ||
/.idea/assetWizardSettings.xml | ||
.DS_Store | ||
/build | ||
/captures | ||
.externalNativeBuild |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<module external.linked.project.id="SmartDoctor" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> | ||
<component name="FacetManager"> | ||
<facet type="java-gradle" name="Java-Gradle"> | ||
<configuration> | ||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" /> | ||
<option name="BUILDABLE" value="false" /> | ||
</configuration> | ||
</facet> | ||
</component> | ||
<component name="NewModuleRootManager" inherit-compiler-output="true"> | ||
<exclude-output /> | ||
<content url="file://$MODULE_DIR$"> | ||
<excludeFolder url="file://$MODULE_DIR$/.gradle" /> | ||
<excludeFolder url="file://$MODULE_DIR$/build" /> | ||
</content> | ||
<orderEntry type="inheritedJdk" /> | ||
<orderEntry type="sourceFolder" forTests="false" /> | ||
</component> | ||
</module> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package buffml.com.smartdoctor | ||
|
||
import android.content.res.AssetManager | ||
import android.graphics.Bitmap | ||
import android.util.Log | ||
import org.tensorflow.lite.Interpreter | ||
import java.io.FileInputStream | ||
import java.nio.ByteBuffer | ||
import java.nio.ByteOrder | ||
import java.nio.MappedByteBuffer | ||
import java.nio.channels.FileChannel | ||
import java.util.* | ||
|
||
class Classifier(assetManager: AssetManager, modelPath: String, labelPath: String, inputSize: Int) { | ||
private var INTERPRETER: Interpreter | ||
private var LABEL_LIST: List<String> | ||
private val INPUT_SIZE: Int = inputSize | ||
private val PIXEL_SIZE: Int = 3 | ||
private val IMAGE_MEAN = 0 | ||
private val IMAGE_STD = 255.0f | ||
private val MAX_RESULTS = 3 | ||
private val THRESHOLD = 0.4f | ||
|
||
data class Recognition( | ||
var id: String = "", | ||
var title: String = "", | ||
var confidence: Float = 0F | ||
) { | ||
override fun toString(): String { | ||
return "Title = $title, Confidence = $confidence)" | ||
} | ||
} | ||
|
||
init { | ||
INTERPRETER = Interpreter(loadModelFile(assetManager, modelPath)) | ||
LABEL_LIST = loadLabelList(assetManager, labelPath) | ||
} | ||
|
||
private fun loadModelFile(assetManager: AssetManager, modelPath: String): MappedByteBuffer { | ||
val fileDescriptor = assetManager.openFd(modelPath) | ||
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) | ||
} | ||
|
||
private fun loadLabelList(assetManager: AssetManager, labelPath: String): List<String> { | ||
return assetManager.open(labelPath).bufferedReader().useLines { it.toList() } | ||
|
||
} | ||
|
||
fun recognizeImage(bitmap: Bitmap): List<Classifier.Recognition> { | ||
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, INPUT_SIZE, INPUT_SIZE, false) | ||
val byteBuffer = convertBitmapToByteBuffer(scaledBitmap) | ||
val result = Array(1) { FloatArray(LABEL_LIST.size) } | ||
INTERPRETER.run(byteBuffer, result) | ||
return getSortedResult(result) | ||
} | ||
|
||
|
||
|
||
private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer { | ||
val byteBuffer = ByteBuffer.allocateDirect(4 * INPUT_SIZE * INPUT_SIZE * PIXEL_SIZE) | ||
byteBuffer.order(ByteOrder.nativeOrder()) | ||
val intValues = IntArray(INPUT_SIZE * INPUT_SIZE) | ||
|
||
bitmap.getPixels(intValues, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) | ||
var pixel = 0 | ||
for (i in 0 until INPUT_SIZE) { | ||
for (j in 0 until INPUT_SIZE) { | ||
val `val` = intValues[pixel++] | ||
|
||
byteBuffer.putFloat((((`val`.shr(16) and 0xFF) - IMAGE_MEAN) / IMAGE_STD)) | ||
byteBuffer.putFloat((((`val`.shr(8) and 0xFF) - IMAGE_MEAN) / IMAGE_STD)) | ||
byteBuffer.putFloat((((`val` and 0xFF) - IMAGE_MEAN) / IMAGE_STD)) | ||
} | ||
} | ||
return byteBuffer | ||
} | ||
|
||
|
||
private fun getSortedResult(labelProbArray: Array<FloatArray>): List<Classifier.Recognition> { | ||
Log.d("Classifier", "List Size:(%d, %d, %d)".format(labelProbArray.size,labelProbArray[0].size,LABEL_LIST.size)) | ||
|
||
val pq = PriorityQueue( | ||
MAX_RESULTS, | ||
Comparator<Classifier.Recognition> { | ||
(_, _, confidence1), (_, _, confidence2) | ||
-> java.lang.Float.compare(confidence1, confidence2) * -1 | ||
}) | ||
|
||
for (i in LABEL_LIST.indices) { | ||
val confidence = labelProbArray[0][i] | ||
if (confidence >= THRESHOLD) { | ||
pq.add(Classifier.Recognition("" + i, | ||
if (LABEL_LIST.size > i) LABEL_LIST[i] else "Unknown", confidence) | ||
) | ||
} | ||
} | ||
Log.d("Classifier", "pqsize:(%d)".format(pq.size)) | ||
|
||
val recognitions = ArrayList<Classifier.Recognition>() | ||
val recognitionsSize = Math.min(pq.size, MAX_RESULTS) | ||
for (i in 0 until recognitionsSize) { | ||
recognitions.add(pq.poll()) | ||
} | ||
return recognitions | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package buffml.com.smartdoctor | ||
|
||
import android.support.test.InstrumentationRegistry | ||
import android.support.test.runner.AndroidJUnit4 | ||
|
||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
import org.junit.Assert.* | ||
|
||
/** | ||
* Instrumented test, which will execute on an Android device. | ||
* | ||
* See [testing documentation](http://d.android.com/tools/testing). | ||
*/ | ||
@RunWith(AndroidJUnit4::class) | ||
class ExampleInstrumentedTest { | ||
@Test | ||
fun useAppContext() { | ||
// Context of the app under test. | ||
val appContext = InstrumentationRegistry.getTargetContext() | ||
assertEquals("buffml.com.smartdoctor", appContext.packageName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package buffml.com.smartdoctor | ||
|
||
import android.os.Bundle | ||
import android.widget.Toast | ||
import android.app.Activity | ||
import android.content.Intent | ||
import android.content.pm.ActivityInfo | ||
import android.graphics.Bitmap | ||
import android.graphics.BitmapFactory | ||
import android.graphics.Matrix | ||
import android.os.Build | ||
import android.provider.MediaStore | ||
import android.support.annotation.RequiresApi | ||
import android.support.v7.app.AppCompatActivity | ||
import android.view.Gravity | ||
import kotlinx.android.synthetic.main.activity_main.*; | ||
import java.io.IOException | ||
|
||
class MainActivity : AppCompatActivity() { | ||
private lateinit var mClassifier: Classifier | ||
private lateinit var mBitmap: Bitmap | ||
|
||
private val mCameraRequestCode = 0 | ||
private val mGalleryRequestCode = 2 | ||
|
||
private val mInputSize = 224 | ||
private val mModelPath = "model.tflite" | ||
private val mLabelPath = "labels.txt" | ||
private val mSamplePath = "skin-icon.jpg" | ||
|
||
|
||
@RequiresApi(Build.VERSION_CODES.O) | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT | ||
setContentView(R.layout.activity_main) | ||
mClassifier = Classifier(assets, mModelPath, mLabelPath, mInputSize) | ||
|
||
resources.assets.open(mSamplePath).use { | ||
mBitmap = BitmapFactory.decodeStream(it) | ||
mBitmap = Bitmap.createScaledBitmap(mBitmap, mInputSize, mInputSize, true) | ||
mPhotoImageView.setImageBitmap(mBitmap) | ||
} | ||
|
||
mCameraButton.setOnClickListener { | ||
val callCameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) | ||
startActivityForResult(callCameraIntent, mCameraRequestCode) | ||
} | ||
|
||
mGalleryButton.setOnClickListener { | ||
val callGalleryIntent = Intent(Intent.ACTION_PICK) | ||
callGalleryIntent.type = "image/*" | ||
startActivityForResult(callGalleryIntent, mGalleryRequestCode) | ||
} | ||
mDetectButton.setOnClickListener { | ||
val results = mClassifier.recognizeImage(mBitmap).firstOrNull() | ||
mResultTextView.text= results?.title+"\n Confidence:"+results?.confidence | ||
|
||
} | ||
} | ||
|
||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { | ||
if(requestCode == mCameraRequestCode){ | ||
//Considérons le cas de la caméra annulée | ||
if(resultCode == Activity.RESULT_OK && data != null) { | ||
mBitmap = data.extras!!.get("data") as Bitmap | ||
mBitmap = scaleImage(mBitmap) | ||
val toast = Toast.makeText(this, ("Image crop to: w= ${mBitmap.width} h= ${mBitmap.height}"), Toast.LENGTH_LONG) | ||
toast.setGravity(Gravity.BOTTOM, 0, 20) | ||
toast.show() | ||
mPhotoImageView.setImageBitmap(mBitmap) | ||
mResultTextView.text= "Your photo image set now." | ||
} else { | ||
Toast.makeText(this, "Camera cancel..", Toast.LENGTH_LONG).show() | ||
} | ||
} else if(requestCode == mGalleryRequestCode) { | ||
if (data != null) { | ||
val uri = data.data | ||
|
||
try { | ||
mBitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, uri) | ||
} catch (e: IOException) { | ||
e.printStackTrace() | ||
} | ||
|
||
println("Success!!!") | ||
mBitmap = scaleImage(mBitmap) | ||
mPhotoImageView.setImageBitmap(mBitmap) | ||
|
||
} | ||
} else { | ||
Toast.makeText(this, "Unrecognized request code", Toast.LENGTH_LONG).show() | ||
|
||
} | ||
} | ||
|
||
|
||
fun scaleImage(bitmap: Bitmap?): Bitmap { | ||
val orignalWidth = bitmap!!.width | ||
val originalHeight = bitmap.height | ||
val scaleWidth = mInputSize.toFloat() / orignalWidth | ||
val scaleHeight = mInputSize.toFloat() / originalHeight | ||
val matrix = Matrix() | ||
matrix.postScale(scaleWidth, scaleHeight) | ||
return Bitmap.createBitmap(bitmap, 0, 0, orignalWidth, originalHeight, matrix, true) | ||
} | ||
|
||
} | ||
|
Binary file not shown.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
# PROJECT | ||
SKIN CANCER DETECTION WITH ANDRIOD APP | ||
# SKIN-CANCER-DETECTION-APP | ||
This is a project in which it can check your skin for signs of skin cancer anytime, anywhere. |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
24 changes: 24 additions & 0 deletions
24
androidTest/java/buffml/com/DOCTOR G/ExampleInstrumentedTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package buffml.com.smartdoctor | ||
|
||
import android.support.test.InstrumentationRegistry | ||
import android.support.test.runner.AndroidJUnit4 | ||
|
||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
import org.junit.Assert.* | ||
|
||
/** | ||
* Instrumented test, which will execute on an Android device. | ||
* | ||
* See [testing documentation](http://d.android.com/tools/testing). | ||
*/ | ||
@RunWith(AndroidJUnit4::class) | ||
class ExampleInstrumentedTest { | ||
@Test | ||
fun useAppContext() { | ||
// Context of the app under test. | ||
val appContext = InstrumentationRegistry.getTargetContext() | ||
assertEquals("buffml.com.smartdoctor", appContext.packageName) | ||
} | ||
} |
Empty file.
Oops, something went wrong.