Você pode usar o Firebase ML para rotular objetos reconhecidos em uma imagem. Consulte a visão geral para obter informações sobre os recursos desta API.
Antes de você começar
- Adicione o Firebase ao seu projeto Android , caso ainda não o tenha feito.
- No arquivo Gradle do módulo (nível do aplicativo) (geralmente
<project>/<app-module>/build.gradle.kts
ou<project>/<app-module>/build.gradle
), adicione a dependência para o Firebase ML Biblioteca de visão para Android. Recomendamos usar o Firebase Android BoM para controlar o controle de versão da biblioteca.dependencies {
// Import the BoM for the Firebase platform
implementation(platform("com.google.firebase:firebase-bom:32.8.0"))
// Add the dependency for the Firebase ML Vision library
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-ml-vision'
}Ao usar o Firebase Android BoM , seu aplicativo sempre usará versões compatíveis das bibliotecas do Firebase Android.
Procurando um módulo de biblioteca específico para Kotlin? A partir de outubro de 2023 (Firebase BoM 32.5.0) , tanto os desenvolvedores Kotlin quanto os Java podem depender do módulo da biblioteca principal (para obter detalhes, consulte o FAQ sobre esta iniciativa ).(Alternativa) Adicionar dependências da biblioteca Firebase sem usar o BoM
Se você optar por não usar o Firebase BoM, deverá especificar cada versão da biblioteca do Firebase em sua linha de dependência.
Observe que se você usa várias bibliotecas do Firebase no seu aplicativo, é altamente recomendável usar a BoM para gerenciar as versões da biblioteca, o que garante que todas as versões sejam compatíveis.
dependencies {
// Add the dependency for the Firebase ML Vision library
// When NOT using the BoM, you must specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-ml-vision:24.1.0'
} Se você ainda não habilitou APIs baseadas em nuvem para seu projeto, faça-o agora:
- Abra a página APIs do Firebase ML do console do Firebase.
Se você ainda não atualizou seu projeto para o plano de preços Blaze, clique em Atualizar para fazer isso. (Você será solicitado a atualizar somente se o seu projeto não estiver no plano Blaze.)
Somente projetos no nível Blaze podem usar APIs baseadas em nuvem.
- Se as APIs baseadas em nuvem ainda não estiverem habilitadas, clique em Habilitar APIs baseadas em nuvem .
Agora você está pronto para rotular imagens.
1. Prepare a imagem de entrada
Crie um objetoFirebaseVisionImage
a partir da sua imagem. O rotulador de imagem é executado mais rapidamente quando você usa um Bitmap
ou, se você usa a API camera2, um media.Image
formatado em JPEG, que são recomendados quando possível.Para criar um objeto
FirebaseVisionImage
a partir de um objetomedia.Image
, como ao capturar uma imagem da câmera de um dispositivo, passe o objetomedia.Image
e a rotação da imagem paraFirebaseVisionImage.fromMediaImage()
.Se você usa a biblioteca CameraX , as classes
OnImageCapturedListener
eImageAnalysis.Analyzer
calculam o valor de rotação para você, então você só precisa converter a rotação em uma das constantesROTATION_
do Firebase ML antes de chamarFirebaseVisionImage.fromMediaImage()
:private class YourImageAnalyzer : ImageAnalysis.Analyzer {
private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) {
0 -> FirebaseVisionImageMetadata.ROTATION_0
90 -> FirebaseVisionImageMetadata.ROTATION_90
180 -> FirebaseVisionImageMetadata.ROTATION_180
270 -> FirebaseVisionImageMetadata.ROTATION_270
else -> throw Exception("Rotation must be 0, 90, 180, or 270.")
}
override fun analyze(imageProxy: ImageProxy?, degrees: Int) {
val mediaImage = imageProxy?.image
val imageRotation = degreesToFirebaseRotation(degrees)
if (mediaImage != null) {
val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
// Pass image to an ML Vision API
// ...
}
}
}private class YourAnalyzer implements ImageAnalysis.Analyzer {
private int degreesToFirebaseRotation(int degrees) {
switch (degrees) {
case 0:
return FirebaseVisionImageMetadata.ROTATION_0;
case 90:
return FirebaseVisionImageMetadata.ROTATION_90;
case 180:
return FirebaseVisionImageMetadata.ROTATION_180;
case 270:
return FirebaseVisionImageMetadata.ROTATION_270;
default:
throw new IllegalArgumentException(
"Rotation must be 0, 90, 180, or 270.");
}
}
@Override
public void analyze(ImageProxy imageProxy, int degrees) {
if (imageProxy == null || imageProxy.getImage() == null) {
return;
}
Image mediaImage = imageProxy.getImage();
int rotation = degreesToFirebaseRotation(degrees);
FirebaseVisionImage image =
FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
// Pass image to an ML Vision API
// ...
}
}Se você não usa uma biblioteca de câmeras que fornece a rotação da imagem, você pode calculá-la a partir da rotação do dispositivo e da orientação do sensor da câmera no dispositivo:
private val ORIENTATIONS = SparseIntArray()
init {
ORIENTATIONS.append(Surface.ROTATION_0, 90)
ORIENTATIONS.append(Surface.ROTATION_90, 0)
ORIENTATIONS.append(Surface.ROTATION_180, 270)
ORIENTATIONS.append(Surface.ROTATION_270, 180)
}
/**
* Get the angle by which an image must be rotated given the device's current
* orientation.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Throws(CameraAccessException::class)
private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
// Get the device's current rotation relative to its "native" orientation.
// Then, from the ORIENTATIONS table, look up the angle the image must be
// rotated to compensate for the device's rotation.
val deviceRotation = activity.windowManager.defaultDisplay.rotation
var rotationCompensation = ORIENTATIONS.get(deviceRotation)
// On most devices, the sensor orientation is 90 degrees, but for some
// devices it is 270 degrees. For devices with a sensor orientation of
// 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
val sensorOrientation = cameraManager
.getCameraCharacteristics(cameraId)
.get(CameraCharacteristics.SENSOR_ORIENTATION)!!
rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
// Return the corresponding FirebaseVisionImageMetadata rotation value.
val result: Int
when (rotationCompensation) {
0 -> result = FirebaseVisionImageMetadata.ROTATION_0
90 -> result = FirebaseVisionImageMetadata.ROTATION_90
180 -> result = FirebaseVisionImageMetadata.ROTATION_180
270 -> result = FirebaseVisionImageMetadata.ROTATION_270
else -> {
result = FirebaseVisionImageMetadata.ROTATION_0
Log.e(TAG, "Bad rotation value: $rotationCompensation")
}
}
return result
}private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
/**
* Get the angle by which an image must be rotated given the device's current
* orientation.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private int getRotationCompensation(String cameraId, Activity activity, Context context)
throws CameraAccessException {
// Get the device's current rotation relative to its "native" orientation.
// Then, from the ORIENTATIONS table, look up the angle the image must be
// rotated to compensate for the device's rotation.
int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int rotationCompensation = ORIENTATIONS.get(deviceRotation);
// On most devices, the sensor orientation is 90 degrees, but for some
// devices it is 270 degrees. For devices with a sensor orientation of
// 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
int sensorOrientation = cameraManager
.getCameraCharacteristics(cameraId)
.get(CameraCharacteristics.SENSOR_ORIENTATION);
rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
// Return the corresponding FirebaseVisionImageMetadata rotation value.
int result;
switch (rotationCompensation) {
case 0:
result = FirebaseVisionImageMetadata.ROTATION_0;
break;
case 90:
result = FirebaseVisionImageMetadata.ROTATION_90;
break;
case 180:
result = FirebaseVisionImageMetadata.ROTATION_180;
break;
case 270:
result = FirebaseVisionImageMetadata.ROTATION_270;
break;
default:
result = FirebaseVisionImageMetadata.ROTATION_0;
Log.e(TAG, "Bad rotation value: " + rotationCompensation);
}
return result;
}Em seguida, passe o objeto
media.Image
e o valor de rotação paraFirebaseVisionImage.fromMediaImage()
:val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
- Para criar um objeto
FirebaseVisionImage
a partir de um URI de arquivo, passe o contexto do aplicativo e o URI do arquivo paraFirebaseVisionImage.fromFilePath()
. Isso é útil quando você usa uma intentACTION_GET_CONTENT
para solicitar que o usuário selecione uma imagem do aplicativo de galeria.val image: FirebaseVisionImage
try {
image = FirebaseVisionImage.fromFilePath(context, uri)
} catch (e: IOException) {
e.printStackTrace()
}FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(context, uri);
} catch (IOException e) {
e.printStackTrace();
} - Para criar um objeto
FirebaseVisionImage
a partir de umByteBuffer
ou de uma matriz de bytes, primeiro calcule a rotação da imagem conforme descrito acima para a entradamedia.Image
.Em seguida, crie um objeto
FirebaseVisionImageMetadata
que contenha a altura, a largura, o formato de codificação de cores e a rotação da imagem:val metadata = FirebaseVisionImageMetadata.Builder()
.setWidth(480) // 480x360 is typically sufficient for
.setHeight(360) // image recognition
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
.setRotation(rotation)
.build()FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(480) // 480x360 is typically sufficient for
.setHeight(360) // image recognition
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
.setRotation(rotation)
.build();Use o buffer ou array e o objeto de metadados para criar um objeto
FirebaseVisionImage
:val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
// Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
// Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata); - Para criar um objeto
FirebaseVisionImage
a partir de um objetoBitmap
: A imagem representada pelo objetoval image = FirebaseVisionImage.fromBitmap(bitmap)
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Bitmap
deve estar na vertical, sem necessidade de rotação adicional.
2. Configure e execute o rotulador de imagens
Para rotular objetos em uma imagem, passe o objetoFirebaseVisionImage
para o método processImage
do FirebaseVisionImageLabeler
.Primeiro, obtenha uma instância de
FirebaseVisionImageLabeler
.val labeler = FirebaseVision.getInstance().getCloudImageLabeler()
// Or, to set the minimum confidence required:
// val options = FirebaseVisionCloudImageLabelerOptions.Builder()
// .setConfidenceThreshold(0.7f)
// .build()
// val labeler = FirebaseVision.getInstance().getCloudImageLabeler(options)FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance()
.getCloudImageLabeler();
// Or, to set the minimum confidence required:
// FirebaseVisionCloudImageLabelerOptions options =
// new FirebaseVisionCloudImageLabelerOptions.Builder()
// .setConfidenceThreshold(0.7f)
// .build();
// FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance()
// .getCloudImageLabeler(options);Em seguida, passe a imagem para o método
processImage()
:labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}labeler.processImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionImageLabel> labels) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});
3. Obtenha informações sobre objetos rotulados
Se a operação de rotulagem da imagem for bem-sucedida, uma lista de objetosFirebaseVisionImageLabel
será transmitida ao listener de sucesso. Cada objeto FirebaseVisionImageLabel
representa algo que foi rotulado na imagem. Para cada rótulo, você pode obter a descrição do texto do rótulo, seu ID de entidade do Knowledge Graph (se disponível) e a pontuação de confiança da correspondência. Por exemplo: for (label in labels) {
val text = label.text
val entityId = label.entityId
val confidence = label.confidence
}
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
String entityId = label.getEntityId();
float confidence = label.getConfidence();
}
Próximos passos
- Antes de implantar em produção um aplicativo que usa uma API do Cloud, você deve seguir algumas etapas adicionais para evitar e mitigar o efeito do acesso não autorizado à API .