With ML Kit's GenAI Image Description API, you can generate short content descriptions for images. This can be useful in the following use cases:
- Generating titles of images
- Generating alternative text (alt text) to help visually impaired users better understand the content of images
- Using generated descriptions as metadata to help users search or organize images
- Utilizing short descriptions of images when the user is unable to look at their screen, such as when they are driving or listening to a podcast
Key capabilities
- Return a short description for an input image
Example results
Input | Output |
![]() |
A small, green Android robot with a cactus-like design sits on a black surface. |
![]() |
A small, white dog with a black nose and pink tongue runs across a grassy field with a bridge in the background. |
Getting Started
To get started with the GenAI Image Description API, add this dependency to your project's build file.
implementation("com.google.mlkit:genai-image-description:1.0.0-beta1")
To integrate the Image Description API into your app, you will begin by getting
an ImageDescriber
client. You must then check the status of the necessary
on-device model features and download the model if it isn't already on the
device. After preparing your image input in an ImageDescriptionRequest
,
you run the inference using the client to obtain the image description text, and
finally, remember to close the client to release resources.
Kotlin
// Create an image describer
val options = ImageDescriberOptions.builder(context).build()
val imageDescriber = ImageDescription.getClient(options)
suspend fun prepareAndStartImageDescription(
bitmap: Bitmap
) {
// Check feature availability, status will be one of the following:
// UNAVAILABLE, DOWNLOADABLE, DOWNLOADING, AVAILABLE
val featureStatus = imageDescriber.checkFeatureStatus().await()
if (featureStatus == FeatureStatus.DOWNLOADABLE) {
// Download feature if necessary.
// If downloadFeature is not called, the first inference request
// will also trigger the feature to be downloaded if it's not
// already downloaded.
imageDescriber.downloadFeature(object : DownloadCallback {
override fun onDownloadStarted(bytesToDownload: Long) { }
override fun onDownloadFailed(e: GenAiException) { }
override fun onDownloadProgress(totalBytesDownloaded: Long) {}
override fun onDownloadCompleted() {
startImageDescriptionRequest(bitmap, imageDescriber)
}
})
} else if (featureStatus == FeatureStatus.DOWNLOADING) {
// Inference request will automatically run once feature is
// downloaded.
// If Gemini Nano is already downloaded on the device, the
// feature-specific LoRA adapter model will be downloaded
// very quickly. However, if Gemini Nano is not already
// downloaded, the download process may take longer.
startImageDescriptionRequest(bitmap, imageDescriber)
} else if (featureStatus == FeatureStatus.AVAILABLE) {
startImageDescriptionRequest(bitmap, imageDescriber)
}
}
fun startImageDescriptionRequest(
bitmap: Bitmap,
imageDescriber: ImageDescriber
) {
// Create task request
val imageDescriptionRequest = ImageDescriptionRequest
.builder(bitmap)
.build()
}
// Run inference with a streaming callback
val imageDescriptionResultStreaming =
imageDescriber.runInference(imageDescriptionRequest) { outputText ->
// Append new output text to show in UI
// This callback is called incrementally as the description
// is generated
}
// You can also get a non-streaming response from the request
// val imageDescription = imageDescriber.runInference(
// imageDescriptionRequest).await().description
}
// Be sure to release the resource when no longer needed
// For example, on viewModel.onCleared() or activity.onDestroy()
imageDescriber.close()
Java
// Create an image describer
ImageDescriberOptions options = ImageDescriberOptions.builder(context).build();
ImageDescriber imageDescriber = ImageDescription.getClient(options);
void prepareAndStartImageDescription(
Bitmap bitmap
) throws ExecutionException, InterruptedException {
// Check feature availability, status will be one of the following:
// UNAVAILABLE, DOWNLOADABLE, DOWNLOADING, AVAILABLE
try {
int featureStatus = imageDescriber.checkFeatureStatus().get();
if (featureStatus == FeatureStatus.DOWNLOADABLE) {
// Download feature if necessary.
// If downloadFeature is not called, the first inference request
// will also trigger the feature to be downloaded if it's not
// already downloaded.
imageDescriber.downloadFeature(new DownloadCallback() {
@Override
public void onDownloadCompleted() {
startImageDescriptionRequest(bitmap, imageDescriber);
}
@Override
public void onDownloadFailed(GenAIException e) {}
@Override
public void onDownloadProgress(long totalBytesDownloaded) {}
@Override
public void onDownloadStarted(long bytesDownloaded) {}
});
} else if (featureStatus == FeatureStatus.DOWNLOADING) {
// Inference request will automatically run once feature is
// downloaded.
// If Gemini Nano is already downloaded on the device, the
// feature-specific LoRA adapter model will be downloaded
// very quickly. However, if Gemini Nano is not already
// downloaded, the download process may take longer.
startImageDescriptionRequest(bitmap, imageDescriber);
} else if (featureStatus == FeatureStatus.AVAILABLE) {
startImageDescriptionRequest(bitmap, imageDescriber);
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
void startImageDescriptionRequest(
Bitmap bitmap,
ImageDescriber imageDescriber
) {
// Create task request
ImageDescriptionRequest imageDescriptionRequest =
ImageDescriptionRequest.builder(bitmap).build();
// Start image description request with streaming response
imageDescriber.runInference(imageDescriptionRequest, newText -> {
// Append new output text to show in UI
// This callback is called incrementally as the description
// is generated
});
// You can also get a non-streaming response from the request
// String imageDescription = imageDescriber.runInference(
// imageDescriptionRequest).get().getDescription();
}
// Be sure to release the resource when no longer needed
// For example, on viewModel.onCleared() or activity.onDestroy()
imageDescriber.close();
Supported features and limitations
The GenAI Image Description API supports English, with support for more languages to be added in the future. The API returns one short description of the image.
Availability of the specific feature configuration (specified by
ImageDescriberOptions
) may vary depending on the particular device's
configuration and the models that have been downloaded to the device.
The most reliable way for developers to ensure that the intended API feature is
supported on a device with the requested ImageDescriberOptions
is to call the
checkFeatureStatus()
method. This method provides the definitive status
of feature availability on the device at runtime.
Common setup issues
ML Kit GenAI APIs rely on the Android AICore app to access Gemini Nano. When a device is just setup (including reset), or the AICore app is just reset (e.g. clear data, uninstalled then reinstalled), the AICore app may not have enough time to finish initialization (including downloading latest configurations from server). As a result, the ML Kit GenAI APIs may not function as expected. Here are the common setup error messages you may see and how to handle them:
Example error message | How to handle |
AICore failed with error type 4-CONNECTION_ERROR and error code 601-BINDING_FAILURE: AICore service failed to bind. | This could happen when you install the app using ML Kit GenAI APIs immediately after device setup or when AICore is uninstalled after your app is installed. Updating AICore app then reinstalling your app should fix it. |
AICore failed with error type 3-PREPARATION_ERROR and error code 606-FEATURE_NOT_FOUND: Feature ... is not available. |
This could happen when AICore hasn't finished downloading the latest configurations. Keep network connection and wait for a few minutes to a few hours.
Note that if the device's bootloader is unlocked, you'll also see this error—this API does not support devices with unlocked bootloaders. |
AICore failed with error type 1-DOWNLOAD_ERROR and error code 0-UNKNOWN: Feature ... failed with failure status 0 and error esz: UNAVAILABLE: Unable to resolve host ... | Keep network connection, wait for a few minutes and retry. |