Tworzenie pierwszej aplikacji Computer Vision na Androida lub iOS

1. Zanim zaczniesz

Z tego modułu dowiesz się, jak utworzyć aplikację obsługującą podstawowe przypadki użycia technologii Computer Vision, wykrywającą główną zawartość obrazu. Nazywa się to zwykle klasyfikacją obrazów lub etykietowaniem obrazów.

Wymagania wstępne

Te ćwiczenia są częścią ścieżki Pierwsze kroki z klasyfikacją obrazów. Jest przeznaczona dla doświadczonych programistów, którzy dopiero zaczynają korzystać z systemów uczących się.

Co stworzysz

  • Aplikacja na Androida umożliwiająca sklasyfikowanie obrazu kwiatu
  • (Opcjonalnie) aplikacja na iOS sklasyfikowająca obraz kwiatu

Czego potrzebujesz

  • Android Studio jest dostępne na https://developer.android.com/studio w sekcji ćwiczeń z programowania na Androida.
  • Xcode (dostępny w Apple App Store) na potrzeby ćwiczeń z programowania na iOS

2. Rozpocznij

Computer Vision to pole z większej dziedziny systemów uczących się, które odkrywa nowe sposoby przetwarzania i wydobywania informacji z obrazu. W sytuacji, gdy komputer zapisał tylko rzeczywiste dane obrazu (takie jak wartości pikseli na obrazie), rozpoznawanie obrazów umożliwia komputerowi analizę zawartości obrazu i pobieranie informacji o jego zawartości.

Na przykład w polu widzenia komputera obraz kota może zostać oznaczony etykietą nie tylko jako piksel obrazu, ale również jako kot. Istnieją też inne pola, które umożliwiają rozpoznawanie obrazu bardziej szczegółowo, np. wykrywanie obiektów, w którym komputer znajduje na zdjęciu wiele elementów i wybiera te ramki.

Z tego modułu ćwiczeń dowiesz się, jak utworzyć aplikację obsługującą podstawowe przypadki użycia, wykrywając główną zawartość obrazu. Nazywa się to zwykle klasyfikacją obrazów lub etykietowaniem obrazów.

Aby aplikacja była jak najprostsza, używa obrazów połączonych w pakiet z zasobami i wyświetla ich klasyfikację. Przyszłe rozszerzenia mogą polegać na użyciu selektora obrazów lub pobrania obrazów bezpośrednio z aparatu.

Zaczniesz od utworzenia aplikacji na Androida za pomocą Android Studio. (Przejdź do kroku 7, by wykonać odpowiednik w iOS).

  1. Otwórz Android Studio, przejdź do menu Plik i wybierz Utwórz nowy projekt.
  2. Poprosimy Cię o wybranie szablonu projektu. Wybierz pustą aktywność.

859b1875e37c321a.png

  1. Kliknij Dalej. Poprosimy Cię o skonfigurowanie projektu. Możesz nadać mu dowolną nazwę i własną nazwę pakietu, ale przykładowy kod w ćwiczeniach z programowania korzysta z nazwy projektu ImageClassifierStep1 i nazwy pakietu com.google.imageclassifierstep1.

ee3b6a81bad87b3.png

  1. Wybierz preferowany język – Kotlin lub Java. W tym module korzystamy z Kotlina, więc jeśli chcesz śledzić jego dokładną wersję, najlepiej wybierz Kotlin.
  2. Gdy wszystko będzie gotowe, kliknij Zakończ. Android Studio utworzy tę aplikację za Ciebie. Skonfigurowanie usługi może zająć kilka minut.

3. Importuj bibliotekę etykiet obrazów ML Kit

ML Kit (https://developers.google.com/ml-kit) oferuje wiele rozwiązań dla programistów, spełnia popularne scenariusze dotyczące systemów uczących się oraz ułatwia wdrożenie i działanie na wielu platformach. ML Kit oferuje gotowe biblioteki, których możesz używać w aplikacji o nazwie Etykiety obrazów. Ta biblioteka zawiera model wytrenowany tak, by rozpoznawał ponad 600 klasy obrazów. dlatego świetnie nadaje się do tego.

Pamiętaj, że ML Kit umożliwia również używanie modeli niestandardowych za pomocą tego samego interfejsu API. Gdy wszystko będzie gotowe, możesz przejść dalej i utworzyć aplikację do personalizowania etykiet obrazów na podstawie modelu wytrenowanego z myślą o Twoim scenariuszu.

W tym przykładzie zbudujesz rozpoznawanie kwiatów. Gdy utworzysz pierwszą aplikację i wyświetlisz jej zdjęcie kwiatu, będzie on rozpoznawany jako kwiat. Później, gdy utworzysz własny model wzorca do wykrywania kwiatów, możesz go upuścić w aplikacji dzięki minimalnym zmianom dzięki nowemu modelowi ML Kit. Nowy model poinformuje Cię, jaki to rodzaj kwiatu, na przykład tulipan lub róża.

  1. W Eksploratorze projektów w Android Studio wybierz Android u góry.
  2. Otwórz folder Gradle Scripts i wybierz plik build.gradle aplikacji. Być może są 2 lub więcej, więc upewnij się, że korzystasz z poziomu aplikacji, jak pokazano tutaj:

93c2e157136671aa.png

  1. U dołu pliku zobaczysz sekcję o nazwie zależności, w której są przechowywane ustawienia implementation, testImplementation i androidImplementation. Dodaj nową do pliku za pomocą tego kodu:
implementation 'com.google.mlkit:image-labeling:17.0.3'

(Upewnij się, że znajduje się wewnątrz zależności { })

  1. W górnej części okna pojawi się pasek z informacją, że build.gradle się zmienił, i musisz przeprowadzić ponowną synchronizację. Śmiało, zrób to. Jeśli go nie widzisz, poszukaj ikony małej słoni na pasku narzędzi w prawym górnym rogu i kliknij ją.

5ef40c7a719077a0.png

Udało Ci się zaimportować ML Kit i możesz rozpocząć dodawanie etykiet do obrazów.

Następnie tworzysz prosty interfejs do renderowania obrazu i umieszczasz w nim przycisk, który po kliknięciu go przez użytkownika wywołuje model narzędzia do oznaczania obrazów do analizy zawartości obrazu.

4. Tworzenie interfejsu

W Android Studio możesz edytować interfejs każdego ekranu (lub Aktywność) przy użyciu pliku układu XML. Podstawowa aplikacja, która została przez Ciebie utworzona, ma 1 aktywność (jej kod znajduje się w regionie MainActivity i wkrótce to zobaczysz), a deklaracja interfejsu użytkownika to activity_main.xml.

Znajdziesz go w folderze res > układ w eksploratorze projektu Androida w ten sposób:

3ed772e9563061e9.png

Otworzy się pełny edytor, który pozwoli Ci zaprojektować interfejs aktywności. Jest ich sporo, a celem tego modułu nie jest nauczenie Cię, jak z niego korzystać. Więcej informacji o edytorze układu znajdziesz na stronie https://developer.android.com/studio/write/layout-editor

Na potrzeby tego modułu wybierz narzędzie Kod w prawym górnym rogu edytora.

1f7dbdef48d9ade6.png

W głównej części okna zobaczysz tylko kod XML. Zmień kod na taki:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/imageToLabel"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <Button
            android:id="@+id/btnTest"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Label Image"
            android:layout_gravity="center"/>
        <TextView
            android:id="@+id/txtOutput"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:gravity="start|top" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Uzyskasz dzięki temu prosty układ z elementem ImageView (renderowanie obrazu), obiektem Button (aby użytkownik mógł nacisnąć obraz) i elementem TextView, w którym będą wyświetlane etykiety.

Interfejs użytkownika jest teraz zdefiniowany. Zanim zaczniesz tworzyć kod, dodaj kilka obrazów jako zasoby – aplikacja o nich będzie wnioskować.

5. Łączenie obrazów z aplikacją

Jednym ze sposobów na grupowanie dodatkowych plików z aplikacją na Androida jest dodanie ich jako zasobów skompilowanych w aplikacji. Zrobimy to, aby dodać zdjęcie niektórych kwiatów. Później możesz rozszerzyć tę aplikację na Aparat X lub inne, aby robić zdjęcia i korzystać z tych funkcji. Jednak dla uproszczenia na razie pogrupujemy obraz.

  1. W eksploratorze projektu w górnej części aplikacji kliknij prawym przyciskiem myszy i wybierz Nowy katalog.
  2. W wyświetlonym oknie z listą różnych katalogów wybierz src/main/assets.

C93650EA68bb60e9.png

Gdy to zrobisz, w eksploratorze projektu zobaczysz nowy folder assets:

444b4afab73433b8.png

  1. Kliknij ten folder prawym przyciskiem myszy, a pojawi się wyskakujące okienko z listą opcji. Jednym z nich jest otwarcie folderu w systemie plików. Wybierz odpowiednią dla swojego systemu operacyjnego i wybierz ją. Na Macu będzie to Reveal Finder, w systemie Windows – Open in Explorer (Otwórz w Eksploratorze), a w systemie Ubuntu – Show in Files.

95e0eca881d35f6b.png

  1. Skopiuj do niego plik. Możesz pobierać obrazy z takich witryn jak Pixabay. Zalecamy zmianę nazwy obrazu na prostą. W tym przypadku jego nazwa została zmieniona na flower1.jpg.

Gdy to zrobisz, wróć do Android Studio, gdzie plik powinien się pojawić w folderze zasobów.

gk53c9c75a033d8.png

Teraz możesz oznaczyć to zdjęcie etykietą.

6. Wpisz kod klasyfikacji, aby oznaczyć obraz etykietą

(Ale teraz ta część, na którą wszyscy czekali, to Komputerowe rozpoznawanie obrazów na Androida).

  1. Wpisz swój kod w pliku MainActivity, więc znajdziesz go w folderze projektu pod adresem com.google.devrel.imageclassifierstep1 (lub innej wolnej przestrzeni nazw, jeśli wybierzesz inną). W projekcie Android Studio skonfigurowano zwykle 3 foldery przestrzeni nazw – jeden dla aplikacji, jeden dla testu Android i jeden dla testów. MainActivity znajdzie się w tym nawiasie, który nie ma opisu w nawiasie.

b5aef8dd5e26b6c2.png

Jeśli chcesz korzystać z Kotlin, możesz się zastanawiać, dlaczego folder nadrzędny nosi nazwę Java. To historyczny artefakt z czasów, gdy Android Studio był tylko językiem Java. Może to rozwiązać ten problem, ale nie ma powodu do obaw, jeśli chcesz używać Kotlin, to nadal działa. To tylko nazwa folderu z kodem źródłowym.

  1. Otwórz plik MainActivity, a w edytorze kodu zobaczysz plik zajęć o nazwie MainActivity. Powinien on wyglądać podobnie do tego:
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

Pod nawiasem klamrowym zamykającym możesz dodać kod rozszerzenia, który nie jest częścią klasy, ale może być używany przez klasę. Aby odczytać plik z zasobów jako bitmapę, musisz mieć rozszerzenie. Służy on do wczytywania wcześniej skopiowanego obrazu do folderu zasobów.

  1. Dodaj ten kod:
// extension function to get bitmap from assets
fun Context.assetsToBitmap(fileName: String): Bitmap?{
    return try {
        with(assets.open(fileName)){
            BitmapFactory.decodeStream(this)
        }
    } catch (e: IOException) { null }
}

Na tym etapie Android Studio prawdopodobnie skarży się i wyróżnia część kodu czerwoną kolorem, np. Context, Bitmap i IOException:

d2bde17e3c04aeed.png

To nie szkodzi. Wynika to z tego, że biblioteki, które je zawierają, nie zostały jeszcze zaimportowane. Android Studio to poręczny skrót.

  1. Najedź kursorem na słowo i naciśnij Alt + Enter (Option + Enter na Macu), a importowanie zostanie wygenerowane.
  2. Następnie możesz załadować bitmapę z zasobów i umieścić ją w elemencie ImageView. Wróć do tagu onCreateFunction w sekcji ActivityActivity i dodaj ten kod pod wierszem setContentView:
val img: ImageView = findViewById(R.id.imageToLabel)
// assets folder image file name with extension
val fileName = "flower1.jpg"
// get bitmap from assets folder
val bitmap: Bitmap? = assetsToBitmap(fileName)
bitmap?.apply {
    img.setImageBitmap(this)
}
  1. Tak jak wcześniej, niektóre fragmenty kodu są zaznaczone na czerwono. Najedź kursorem na ten wiersz i kliknij Alt + Enter / Opcja + Enter, aby automatycznie dodać zaimportowane dane.
  2. W utworzonym wcześniej pliku layout.xml napisano element ImageView o nazwie imageToLabel, więc pierwszy wiersz tworzy wystąpienie obiektu ImageView o nazwie img z informacjami o tym układzie. Wyszukuje szczegóły za pomocą wbudowanej funkcji Androida findViewById. Następnie wykorzystuje nazwę pliku flower1.jpg do wczytania obrazu z folderu zasobów przy użyciu funkcji assetsToBitmap utworzonej w poprzednim kroku. Wykorzystuje też abstrakcyjną klasę bitmap do wczytywania bitmapa do obrazu img.
  3. Plik układu zawierał element TextView, który będzie służył do renderowania etykiet ustalonych dla obrazu. Pobierz obiekt kodu do tego zdarzenia. Dodaj kod bezpośrednio pod poprzednim kodem:
val txtOutput : TextView = findViewById(R.id.txtOutput)

Do tej pory znajduje on informacje o układzie w widoku tekstu, używając jego nazwy (sprawdź plik XML, w którym nosi nazwę txtOutput), i wykorzystuje je do utworzenia obiektu TextView o nazwie txtoutput.

I podobnie tworzy się przycisk do reprezentowania tego przycisku i tworzy go w treści pliku układu.

W układzie z nazwą przycisku nazwaliśmy przycisk btnTest, abyśmy mogli utworzyć instancję w ten sposób:

val btn: Button = findViewById(R.id.btnTest)

Po zainicjowaniu kodu i elementów sterujących następnym (i ostatnim) krokiem będzie ich użycie do ustalenia obrazu.

Zanim przejdziesz dalej, upewnij się, że Twój kod onCreate wygląda tak:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val img: ImageView = findViewById(R.id.imageToLabel)
    // assets folder image file name with extension
    val fileName = "flower1.jpg"
    // get bitmap from assets folder
    val bitmap: Bitmap? = assetsToBitmap(fileName)
    bitmap?.apply {
        img.setImageBitmap(this)
    }
    val txtOutput : TextView = findViewById(R.id.txtOutput)
    val btn: Button = findViewById(R.id.btnTest)
}

Żadne słowo kluczowe nie powinno być oznaczone kolorem czerwonym, co oznacza, że nie zostały one jeszcze zaimportowane. Jeśli tak, wróć i wykonaj Alt + Enter, by wygenerować importy.

Gdy używasz etykietowania obrazów w ML Kit, najpierw musisz utworzyć obiekt Options, aby dostosować to działanie. Przekonwertujesz obraz na format InputImage rozpoznawany przez system ML Kit. Następnie tworzysz obiekt Labeler, aby wykonać wnioskowanie. Otrzymasz asynchroniczne oddzwonienie z wynikami, które możesz przeanalizować.

Na utworzonym przycisku wykonaj wszystkie czynności w ramach wydarzenia onClickListener. Oto pełny kod:

btn.setOnClickListener {
  val labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS)
  val image = InputImage.fromBitmap(bitmap!!, 0)
  var outputText = ""
  labeler.process(image)
    .addOnSuccessListener { labels ->
      // Task completed successfully
      for (label in labels) {
        val text = label.text
        val confidence = label.confidence
        outputText += "$text : $confidence\n"
      }
      txtOutput.text = outputText
  }
    .addOnFailureListener { e ->
      // Task failed with an exception
  }
}
  • Gdy użytkownik kliknie ten przycisk po raz pierwszy, kod utworzy wystąpienie etykiety za pomocą polecenia ImageLabeling.getClient, który przekazuje parametr ImageLabelerOptions. Ta właściwość zawiera właściwość DEFAULT_OPTIONS, która umożliwia szybkie uruchomienie kampanii.
  • Następnie na podstawie mapy bitowej zostanie utworzony obiekt InputImage za pomocą metody fromBitmap. Format ObrazObrazu to preferowany format do przetwarzania obrazów.
  • Etykieta przetworzy obraz i wykonuje asynchroniczne wywołanie zwrotne, które zakończy się powodzeniem lub niepowodzeniem. Jeśli wnioskowanie się powiedzie, wywołanie zwrotne będzie zawierać listę etykiet. Możesz następnie przeanalizować tę listę etykiet, aby odczytać tekst etykiety i wartość ufności. W razie niepowodzenia otrzymasz od nas wyjątek, którego możesz użyć do zgłoszenia tego użytkownika.

Gotowe! Możesz ją teraz uruchomić na urządzeniu z Androidem lub w emulatorze. Więcej informacji znajdziesz tutaj: https://developer.android.com/studio/run/emulator.

Oto aplikacja uruchomiona w emulatorze. Na początku zobaczysz obraz i przycisk, a etykieta będzie pusta.

C07f5f307f070dc7.png

Naciśnij przycisk, aby uzyskać zestaw etykiet do obrazu.

550cca783363551.png

Jak widać, oznacza to, że na zdjęciu znajdowało się wysokie prawdopodobieństwo, że obraz zawierał płatek, kwiat, roślinę i niebo. Wszystkie te dane są prawidłowe – wszystkie pokazują, że model analizuje obraz.

Nie można jednak stwierdzić, że jest to zdjęcie stokrotki. Będzie Ci do tego potrzebny model niestandardowy, który trenuje się na konkretnych kwiatach. W kolejnym module dowiesz się, jak to zrobić.

W kolejnych krokach dowiesz się, jak stworzyć tę samą aplikację na iOS.

7. Tworzenie klasyfikatora obrazów na urządzeniach z iOS – pierwsze kroki

Podobną aplikację możesz utworzyć na iOS za pomocą Xcode.

  1. Uruchom Xcode i z menu plików wybierz New Project (Nowy projekt). Pojawi się to okno dialogowe:

8fb0e6a9d6ac275e.png

  1. Wybierz opcję Aplikacja, jak pokazano, i kliknij Dalej. Pojawi się prośba o wybranie opcji projektu. Nadaj mu nazwę i podaj identyfikator organizacji, jak widać. Upewnij się, że typ interfejsu to Scenboard, a język jest ustawiony na Swift.

76c6bdb5aee7659c.png

  1. Jeśli chcesz wdrożyć aplikację na telefonie i skonfigurować profil dewelopera, możesz skonfigurować ustawienia zespołu. W przeciwnym razie pozostaw wartość Brak i uruchom aplikację w symulatorze iOS.
  2. Kliknij Dalej i wybierz folder, w którym chcesz zapisać projekt i znajdujące się w nim pliki. Zapamiętaj lokalizację tego projektu. Będzie Ci potrzebna w następnym kroku.
  3. Na razie zamknij Xcode, bo w kolejnym kroku otworzysz go ponownie przy użyciu innego pliku obszaru roboczego.

8. Zintegruj ML Kit z użyciem Cocoapods

Ponieważ ML Kit działa też w systemie iOS, możesz go używać do tworzenia klasyfikatorów obrazu w podobny sposób. Do ich integracji będziesz używać CocoaPods. Jeśli jeszcze nie masz tej aplikacji, możesz ją zainstalować, postępując zgodnie z instrukcjami na stronie https://cocoapods.org/

  1. Otwórz katalog, w którym został utworzony projekt. Powinien on zawierać plik .xcodeproj.

Tutaj znajduje się plik .xcodeproj wskazujący lokalizację I'm we właściwym miejscu.

e2966a47e84eb398.png

  1. W tym folderze utwórz nowy plik o nazwie Podfile. Nie ma rozszerzenia, tylko plik Podfile. Dodaj w nim te informacje:
platform :ios, '10.0'

target 'ImageClassifierStep1' do
        pod 'GoogleMLKit/ImageLabeling'
end
  1. Zapisz ją i wróć do terminala. z tego samego typu katalogu: pod install, Cocoapods pobierze odpowiednie biblioteki i zależności, a następnie utworzy nowy obszar roboczy, który połączy Twój projekt z zasobami zewnętrznymi.

3b4c628b0cbface8.png

Od tej pory będzie konieczne zamknięcie sesji Xcode i użycie pliku Workspace. Otwórz ten plik, a Xcode zostanie uruchomiony wraz z oryginalnym projektem oraz z zewnętrznymi zależnościami.

32090e0024b6b5ef.png .

Możesz teraz przejść do następnego kroku i utworzyć interfejs użytkownika.

9. Tworzenie UI na iOS za pomocą scenorysów

  1. Otwórz plik Main.storyboard, a zobaczysz układ interfejsu z obsługą interfejsu telefonu.
  2. W prawym górnym rogu ekranu znajduje się przycisk +, który umożliwia dodawanie elementów sterujących. Kliknij go, aby wyświetlić paletę elementów sterujących.

e63bc3bafa54cc21.png

  1. Następnie przeciągnij i upuść obiekt ImageView, Button (przycisk) i Label (Etykietę) na powierzchnię projektu. Ułóż je na górze tak, jak pokazano:

f9dfc55616b25f11.png

  1. Kliknij dwukrotnie przycisk, aby zmienić jego tekst z Przycisku na Klasyfikuj.
  2. Aby zmienić jej rozmiar, przeciągnij uchwyty sterujące wokół etykiety. Powiedz np., że szerokość elementu UIImageView jest dwa razy większa.
  3. Po wybraniu etykiety kliknij przycisk selektory w prawym górnym rogu, by wyświetlić paletę inspekcji.
  4. Gdy to zrobisz, znajdź ustawienie Linie i sprawdź, czy jest ustawione na 0. Dzięki temu etykieta może renderować dynamiczną liczbę wierszy.

A39708b320b56b30.png

Możesz teraz przejść do następnego kroku – podłączyć interfejs do kodu za pomocą gniazdek i działań.

10. Tworzenie działań i gniazdek

Tworząc scenorysy na iOS, sprawdzaj informacje o układzie elementów sterujących za pomocą gniazd. Definiujesz kod, który ma zostać uruchomiony, gdy użytkownik wykona działanie na elemencie sterującym za pomocą działań.

W następnym kroku musisz utworzyć gniazda na obiekty ImageView i etykietę. Element ImageView zostanie użyty w kodzie, by wczytać do niego obraz. Do etykiety będzie się odwoływać w kodzie, aby ustawić tekst na podstawie wnioskowania z ML Kit.

  1. Aby zamknąć paletę inspekcji, kliknij element sterujący w prawym górnym rogu ekranu, a potem kliknij przycisk Dodaj edytor po prawej stronie, który jest pod nim.

77255f7d6284750.png

  1. Ekran główny będzie nieczytelny, a główny element scenorysu zostanie otwarty dwukrotnie. Po lewej stronie w nawigatorze projektu wybierz ViewController.swift, by otworzyć kod kontrolera widoku danych. Wygląda na to, że Twój panel projektu zniknął z edytora scenorysu po lewej stronie, ale nie martw się – nadal tu jest.
  2. Aby wrócić, kliknij Wyświetl kontroler w widoku kontrolera. Postaraj się, by Twój interfejs wyglądał podobnie do tego: scenorys po lewej stronie przedstawia Twój projekt, a kod po stronie ViewController.swift po prawej.

7eb21c7f9d43c9bc.png

  1. Wybierz UIImageView w panelu projektu po lewej stronie, a następnie naciśnij klawisz CONTROL, przeciągnij go do kodu po prawej stronie i upuść go pod słowem kluczowym class (w wierszu 11 na powyższym zrzucie ekranu).

Podczas przeciągania zobaczysz strzałkę, a gdy upuścisz ikonę, pojawi się wyskakujące okienko:

37477f0611948318.png

  1. Wypełnij pole Nazwa jako „"imageView&quot” i kliknij Połącz.
  2. Powtórz ten proces z etykietą i nadaj mu nazwę "lbloutput."
  3. Ważne: w przypadku przycisku zrób to samo, ale ustaw typ połączenia na Action (Działanie), a nie Outlet.

7281b6eea9fb6c23.png

  1. Nadaj mu nazwę "doClassification", a potem kliknij Connect (Połącz).

Gdy skończysz, Twój kod powinien wyglądać tak: (widok etykiety i obrazu jest zadeklarowany jako IBOutlet (Outlet Builder Outlet), a przycisk jako IBAction (Interface Builder Action).

import UIKit

class ViewController: UIViewController {

    @IBAction func doClassification(_ sender: Any) {
    }
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var lblOutput: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

}
  1. Na koniec połącz obraz z aplikacją, aby ułatwić nam klasyfikację. Aby to zrobić, przeciągnij plik z eksploratora plików do eksploratora po lewej stronie ekranu w Xcode. Gdy to zrobisz, pojawi się takie wyskakujące okienko:

889ff33eaec785ec.png

  1. Sprawdź, czy pole wyboru w sekcji Dodaj do celów jest zaznaczone, a następnie kliknij Zakończ.

Plik zostanie dołączony do Twojej aplikacji. Możesz go teraz łatwo sklasyfikować. Teraz możesz kodować interfejs w celu sklasyfikowania obrazu.

11. Kodowanie do klasyfikacji obrazów

Teraz, gdy wszystko jest skonfigurowane, napisanie kodu do klasyfikacji obrazów jest naprawdę proste.

  1. Najpierw zamknij projekt scenorysu, klikając X w lewym górnym rogu jego panelu. Dzięki temu możesz się skupić tylko na kodzie. W pozostałej części tego modułu będziesz edytować element ControlController.swift.
  2. Zaimportuj biblioteki MLKitVision i MLKit ImageLabeling przez dodanie tego kodu u góry, bezpośrednio po zaimportowaniu interfejsu UIKit:
import MLKitVision
import MLKitImageLabeling
  1. Następnie w funkcji viewDidLoad zainicjuj element ImageView przy użyciu pliku dołączonego do aplikacji:
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    imageView.image = UIImage(named:"flower1.jpg")
}
  1. Utwórz funkcję pomocniczą, aby uzyskać etykiety obrazu bezpośrednio poniżej viewDidLoad():
func getLabels(with image: UIImage){
  1. Utwórz obraz VisionImage z obrazu. ML Kit używa tego typu interfejsu do klasyfikacji obrazów. Zatem, używając funkcji getLabel, dodaj ten kod:
let visionImage = VisionImage(image: image)
visionImage.orientation = image.imageOrientation
  1. Następnie utwórz opcje dla etykiet etykiet obrazów. Za jego pomocą zostaną zainicjowane te opcje. W tym przypadku wystarczy ustawić podstawową opcję elementu confidenceThreshold. Oznacza to, że musisz oznaczać etykietami tylko te etykiety, które mają pewność co najmniej 0,4. Na przykład w przypadku naszego kwiatu klasy takie jak „&plant&quot” czy „"petal"” będą miały dużą pewność, ale takie jak „koszykówka&quot” czy „samochód” będą miały niski poziom ufności.
let options = ImageLabelerOptions()
options.confidenceThreshold = 0.4
  1. Teraz utwórz osoby oznaczające etykietami za pomocą tych opcji:
let labeler = ImageLabeler.imageLabeler(options: options)
  1. Gdy uzyskasz etykietę, możesz ją przetworzyć. Otrzymasz asynchroniczne wywołanie zwrotne z etykietami (jeśli było skuteczne) i błędem (w przypadku niepowodzenia), które możesz następnie przetworzyć za pomocą innej funkcji, którą utworzymy za chwilę.
labeler.process(visionImage) { labels, error in
    self.processResult(from: labels, error: error)
  }

Nie martw się, jeśli Xcode narzeka, że nie ma użytkownika processResult. Właśnie to zostało przez Ciebie zaimplementowane i zrób to później.

Dla ułatwienia podajemy tutaj pełną wersję funkcji getLabel:

// This is called when the user presses the button
func getLabels(with image: UIImage){
    // Get the image from the UI Image element and set its orientation
    let visionImage = VisionImage(image: image)
    visionImage.orientation = image.imageOrientation

    // Create Image Labeler options, and set the threshold to 0.4
    // so we will ignore all classes with a probability of 0.4 or less
    let options = ImageLabelerOptions()
    options.confidenceThreshold = 0.4

    // Initialize the labeler with these options
    let labeler = ImageLabeler.imageLabeler(options: options)

    // And then process the image, with the callback going to self.processresult
    labeler.process(visionImage) { labels, error in
        self.processResult(from: labels, error: error)
 }
}

Teraz musisz zaimplementować funkcję processResult. To bardzo proste, bo mamy etykiety i obiekt błędu. Etykiety należy przesłać do typu ImageLabel z ML Kit.

Gdy to zrobisz, możesz po prostu iterować zestaw etykiet, pobrać opis i wartość ufności, a następnie dodać je do var o nazwie labeltexts. Aby zmienić wszystkie te parametry, wystarczy ustawić wartość lbloutput.text na tę wartość.

Oto pełna funkcja:

// This gets called by the labeler's callback
func processResult(from labels: [ImageLabel]?, error: Error?){
    // String to hold the labels
    var labeltexts = ""
    // Check that we have valid labels first
    guard let labels = labels else{
        return
    }
  // ...and if we do we can iterate through the set to get the description and confidence
    for label in labels{
        let labelText = label.text + " : " + label.confidence.description + "\n"
        labeltexts += labelText
    }
    // And when we're done we can update the UI with the list of labels
    lblOutput.text = labeltexts
}

Pozostało tylko wywołać funkcję getLabels, gdy użytkownik naciśnie przycisk.

Gdy udało Ci się wykonać daną czynność, potrzebne było połączenie z Twoim kontem. Dlatego aby utworzyć połączenie o nazwie getLabels, musisz zaktualizować utworzoną wcześniej usługę IBAction o nazwie doClassificaiton.

Oto kod, który wywołuje go z treścią elementu imageView:

@IBAction func doClassification(_ sender: Any) {
    getLabels(with: imageView.image!)
}

Teraz możesz ją wypróbować. Możesz zobaczyć, jak to działa:

eb8e6c1b2e2c65e0.png

Pamiętaj, że układ może się różnić w zależności od urządzenia.

Ćwiczenia z programowania nie są poświęcone różnym typom układów na poszczególnych urządzeniach, co jest dość skomplikowane. Jeśli interfejs nie wyświetla się prawidłowo, wróć do edytora scenorysu, a na dole zobaczysz sekcję Wyświetl jako:, w której możesz wybrać konkretne urządzenie. Wybierz urządzenie, aby dopasować je do obrazu lub urządzenia, na którym testujesz aplikację, i dopasować odpowiednio interfejs.

W miarę jak będziesz rozwijać program iOS, nauczysz się używać ograniczeń, aby mieć pewność, że interfejs jest spójny dla wszystkich telefonów, ale ta funkcja wykracza poza zakres tego modułu.

12. Gratulacje!

Masz teraz wdrożoną aplikację zarówno na Androida, jak i na iOS, dając Ci podstawową możliwość rozpoznawania obrazów za pomocą ogólnego modelu. Najważniejsza ciężka praca została już wykonana.

W ramach kolejnego ćwiczenia z programowania stworzysz model niestandardowy, który będzie rozpoznawał różnego rodzaju kwiaty, i za pomocą zaledwie kilku wierszy kodu zaimplementujesz go w tej aplikacji, by był jeszcze bardziej przydatny.