Skip to content

Commit

Permalink
design and some code clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex-Kopylov committed Mar 22, 2020
1 parent 9f541ec commit 39af97d
Show file tree
Hide file tree
Showing 17 changed files with 211 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
Expand All @@ -21,38 +22,28 @@ import java.io.ByteArrayOutputStream


class CapturePhotoFragment : Fragment() {
private lateinit var camera: ImageView
private lateinit var camera: TextView
private lateinit var btnCapturePhoto: Button
private lateinit var intent:Intent
private val intent= Intent(MediaStore.ACTION_IMAGE_CAPTURE)
private lateinit var textClass:TextView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(
intent,
CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE)
startCamera()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {

// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_capture_photo, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {


btnCapturePhoto = btn_capture_photo
camera = img_view_camera
textClass = text_view_class
btnCapturePhoto.setOnClickListener {
startActivityForResult(
intent,
CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE)
startCamera()
}

}
Expand All @@ -68,33 +59,33 @@ class CapturePhotoFragment : Fragment() {
val stream = ByteArrayOutputStream()
bmp!!.compress(Bitmap.CompressFormat.PNG, 100, stream)
val byteArray: ByteArray = stream.toByteArray()
// convert byte array to Bitmap
val bitmap = BitmapFactory.decodeByteArray(
byteArray, 0,
byteArray.size
)
camera.setImageBitmap(bitmap)
textClass.text = "Loading..."
camera.text=""
camera.setBackgroundDrawable((BitmapDrawable(resources, bitmap)))
textClass.text = "Classifying..."

val imageNetClasses = ImageClassification(bitmap, context!!).objectDetection()
textClass.text = imageNetClasses
btnCapturePhoto.visibility=View.VISIBLE

Thread {
val imgPath =
Utils.getImagePathFromBitmap(context!!, bitmap, title = imageNetClasses)
PictureDao?.insertPicture(Picture(imageNetClasses, imgPath))

//textClass.text = PictureDao!!.getPictures().toString()
db?.pictureDao()?.getPictures()?.forEach() {
Log.i("Fetch Records", "Id: : ${it.id}")
Log.i("Fetch Records", "Classes: : ${it.imageNetClasses}")
Log.i("Fetch Records", "Path: : ${it.imgPath}")
}
}.start()
val imgPath = Utils.getImagePathFromBitmap(context!!, bitmap, title = imageNetClasses)
db?.pictureDao()?.insertPicture(Picture(imageNetClasses, imgPath))
}
else {
camera.text = ""
camera.background = resources.getDrawable(R.drawable.pytorch_logo)
btnCapturePhoto.visibility = View.VISIBLE
}
}
}

private fun startCamera(){
startActivityForResult(
intent,
CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE)
}
companion object {
private const val CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 1888
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ class ImageClassification(bitmap: Bitmap, context: Context) {
)

public fun objectDetection(): String {
val outputTensor = module.forward(IValue.from(inputTensor)).toTensor()
val scores = outputTensor.dataAsFloatArray
val maxScoreIdx = scores.indices.maxBy { scores[it] } ?: -1
val classNames = ImageNetClasses.IMAGENET_CLASSES[maxScoreIdx]
return classNames
}
val outputTensor = module.forward(IValue.from(inputTensor)).toTensor()
val scores = outputTensor.dataAsFloatArray
val maxScoreIdx = scores.indices.maxBy { scores[it] } ?: -1
return ImageNetClasses.IMAGENET_CLASSES[maxScoreIdx]
}

private fun loadModule(context: Context) = Module.load(Utils.assetGetAbsolutePathByName(context, "resnet18.pt"));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example.androidProjectOnTFLite

import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.androidProjectOnTFLite.RoomDB.Picture


class ItemViewHolder(inflater: LayoutInflater, parent: ViewGroup) : RecyclerView.ViewHolder(inflater.inflate(R.layout.item, parent, false)){

private var classes: TextView? = null
private var photo: ImageView? = null

init{
classes = itemView.findViewById(R.id.classesTextView)
photo = itemView.findViewById(R.id.photo)
}

fun bind(pic: Picture){
photo?.setImageURI(Uri.parse(pic.imgPath))
classes?.text = pic.imageNetClasses
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.androidProjectOnTFLite.RoomDB.Picture
import kotlinx.android.synthetic.main.fragment_list_of_classified_images.*

/**
* A simple [Fragment] subclass.
*/
class ListOfClassifiedImagesFragment : Fragment() {

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_list_of_classified_images, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.apply{
layoutManager = LinearLayoutManager(activity)
adapter = RecyclerViewAdapter((db?.pictureDao()?.getPictures() as MutableList<Picture>?)!!)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

//db = AppDatabase.getDatabaseInstance(this)
db = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "pics-database")
db = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "pics-database").allowMainThreadQueries()
.build()
// val host = NavHostFragment.create(R.navigation.nav_graph)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,11 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_menu.*

/**
* A simple [Fragment] subclass.
*/
class MenuFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_menu, container, false)
}

Expand All @@ -25,7 +20,4 @@ class MenuFragment : Fragment() {
toCamera.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_menuFragment_to_capturePhotoFragment))
toList.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_menuFragment_to_listOfClassifiedImagesFragment))
}

//val navController =

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.example.androidProjectOnTFLite

import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.androidProjectOnTFLite.RoomDB.Picture
import kotlinx.android.synthetic.main.item.view.*

class RecyclerViewAdapter(val items: MutableList<Picture>)
: RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(){

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
: ViewHolder {
val v: View = LayoutInflater.from(parent.context)
.inflate(R.layout.item,parent,false)
return ViewHolder(v)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.image.setImageURI(Uri.parse(items[position].imgPath))
holder.classes.text = items[position].imageNetClasses
holder.delete.setOnClickListener { deleteItem(position) }
}

override fun getItemCount(): Int {
return items.size
}

private fun deleteItem(position: Int){
db?.pictureDao()?.delete(items[position]) //from db
items.removeAt(position) //from list
notifyItemRemoved(position) //from screen
notifyItemRangeChanged(position, itemCount)
}
class ViewHolder(itemView:View): RecyclerView.ViewHolder(itemView){
val image: ImageView = itemView.photo
val classes: TextView = itemView.classesTextView
val delete: ImageButton = itemView.btnDelete
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters

@Database(
entities = [Picture::class],
version = 1,
exportSchema = false
)


abstract class AppDatabase : RoomDatabase() {
abstract fun pictureDao(): PictureDao?

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.androidProjectOnTFLite.RoomDB

import android.net.Uri
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package com.example.androidProjectOnTFLite.Utils

import android.content.ContentValues.TAG
import android.content.Context
import android.database.Cursor
import android.graphics.Bitmap
import android.net.Uri
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.text.SimpleDateFormat
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*


object Utils {
fun assetGetAbsolutePathByName(context: Context, assetName: String): String? {
val file = File(context.filesDir, assetName)
Expand All @@ -32,11 +36,13 @@ object Utils {
}
return null
}

fun getImagePathFromBitmap(context: Context, bitmap: Bitmap, title: String = "Title", description: String? = null): String {
val bytes = ByteArrayOutputStream()
val sdf = SimpleDateFormat("-dd.MM.yyyy.HH-mm-ss")
val fileName = title + sdf.format(Date())
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
return MediaStore.Images.Media.insertImage(context.contentResolver, bitmap, fileName, description)
}

}
18 changes: 18 additions & 0 deletions app/src/main/res/drawable/del.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="595.275dp"
android:height="841.891dp"
android:viewportWidth="595.275"
android:viewportHeight="841.891">
<path
android:pathData="M326.039,513.568h-69.557v-9.441c0,-10.531 2.12,-19.876 6.358,-28.034c4.239,-8.156 13.165,-18.527 26.783,-31.117l12.33,-11.176c7.322,-6.678 12.684,-12.973 16.09,-18.882c3.4,-5.907 5.105,-11.817 5.105,-17.727c0,-8.99 -3.084,-16.022 -9.248,-21.098c-6.166,-5.073 -14.773,-7.611 -25.819,-7.611c-10.405,0 -21.646,2.152 -33.719,6.455c-12.075,4.305 -24.663,10.693 -37.765,19.171v-60.5c15.541,-5.395 29.735,-9.375 42.582,-11.946c12.843,-2.568 25.241,-3.854 37.186,-3.854c31.342,0 55.232,6.392 71.678,19.171c16.439,12.783 24.662,31.439 24.662,55.973c0,12.591 -2.506,23.862 -7.516,33.815c-5.008,9.956 -13.553,20.649 -25.625,32.08l-12.332,10.983c-8.736,7.966 -14.451,14.354 -17.148,19.171s-4.045,10.115 -4.045,15.896V513.568zM256.482,542.085h69.557v68.593h-69.557V542.085z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M299.76,439.067m-218.516,0a218.516,218.516 0,1 1,437.032 0a218.516,218.516 0,1 1,-437.032 0"
android:fillColor="#F44336"/>
<path
android:pathData="M184.061,369.552l46.347,-46.347l185.387,185.387l-46.347,46.347z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M369.281,323.371l46.346,46.346l-185.387,185.387l-46.346,-46.346z"
android:fillColor="#FFFFFF"/>
</vector>
Binary file added app/src/main/res/drawable/pytorch_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 39af97d

Please sign in to comment.