nyris is a high performance visual product search, object detection and visual recommendations engine for retail and industry.
For more information please see nyris.io
We provide a new SDK with better error handling and reactive programming support. The SDK is written in Kotlin and compatible with Java.
The old SDK is offering only image matching services and based on asynchronous callback system. This new SDK offers:
- Support of Reactive programming paradigm
- No more asynchronous callback/asyncTask
- Better multithreading handling
- Better error handling
- Type-safe HTTP client
- Unified response
- All the different nyris services
We offer :
- Visual search
- Similarity search by image
- Object detection
- Manual matching
- Text Search
- Similarity search by SKU
- Feedback API
- Android >= 4.0
- Images in JPEG format
- The minimum dimensions of the image are
512x512 px
- The maximum size of the image is less than or equal to
500 KB
- RxJava and RxAndroid
Add the dependencies
repositories {
maven {
url "https://maven.nyris.io/maven2/maven/"
}
}
dependencies {
implementation 'io.nyris:sdk:1.6.1'
implementation "io.reactivex.rxjava2:rxandroid:$rxandroidVersion"
implementation "android.arch.lifecycle:extensions:1.x.x" //Optional
}
- Get instance
- Destroy the instance
- Match your first image
- Extract objects from your image
- Mark sent image as not found
- Text Match Search
- Send user feedback
- Filters
First, initialize an instance of INyris
with your API Key :
class DemoApp : Application(){
private var nyris : INyris
override fun onCreate() {
super.onCreate()
nyris = Nyris.createInstance(BuildConfig.API_KEY)
// OR
nyris = Nyris.createInstance("YOUR_API_KEY", NyrisConfig(isDebug = true))
// OR
nyris = Nyris.createInstance("YOUR_API_KEY", NyrisConfig(
isDebug = true,
hostUrl = "YOUR_HOST_URL"
)
)
}
}
You can easily free all the created instances by adding nyris
to the lifecyle of your main activity
or by calling destroy()
of the sdk
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sample)
lifecycle.addObserver(nyris)
}
// OR
override fun onDestroy(){
super.onDestroy()
nyris.destroy()
}
}
NOTE : to make the SDK fully compatible with lifecycle-aware components you will need to add the missing dependecy
dependencies {
implementation "android.arch.lifecycle:extensions:1.x.x"
}
val imageByteArray : ByteArray = /*Your byte array*/
nyris
.imageMatching()
.match(imageByteArray)
.subscribe({/*it:OfferResponse*/
// Handle your response
val offers = it.offers
},{/* it:Throwable */
when (it) {
is HttpException -> {
...
}
is IOException -> {
...
}
else -> {
// Unknown
}
}
})
Some options are deprecated and they will be removed on the next release 1.8.0
//For more details about available feed attributes please check our documentation : http://docs.nyris.io/#available-feed-attributes.
val imageByteArray : ByteArray = /* Your byte array */
nyris
.imageMatching()
.outputFormat("PROVIDED_OUTPUT_FORMAT") // Set the desired OUTPUT_FORMAT
.language("de") // Return only offers with language "de".
.exact({ //[DEPRECATED]
enabled = false // disable exact matching
})
.similarity({ //[DEPRECATED]
threshold = 0.5F // The lower limit of confidences to be considered good from similarity
limit = 10 // The upper limit for the number of results to be returned from similarity
})
.ocr({ //[DEPRECATED]
enabled = false // disable OCR
})
.regroup({ //[DEPRECATED]
enabled = false // This mode enables regrouping of the items
threshold = 0.5F // The lower limit of confidences to be considered good from similarity
})
.recommendations() //[DEPRECATED]
.categoryPrediction({ //[DEPRECATED]
enabled = true // Enables the output of predicted categories.
threshold = 0.5F // Sets the cutoff threshold for category predictions (range 0..1).
limit = 10 // Limits the number of categories to return.
})
.limit(10) // Limit returned offers
.match(imageTestBytes)
.subscribe({/* it:OfferResponse */
// Handle your response
val offers = it.offers
},{/* it:Throwable */
...
})
The response is an object of type OfferResponse
that contains list of offers
.
- If you specified a custom output format, you should use this call to get response as
JSON
format :
val imageByteArray : ByteArray = /*Your byte array*/
nyris
.imageMatching()
.match<JsonResponseBody>(imageByteArray, JsonResponseBody::class.java)
.subscribe({/* it:JsonResponseBody */
// Handle your response
val json = it.json
},{/*it:Throwable*/
...
})
find objects in an image
nyris
.regions(imageByteArray)
.subscribe({/* it:ObjectList */
// Handle your response
val objects = it
},{/* it:Throwable */
...
})
Returned response is a List of objects.
The extracted object has:
confidence
is the probability of the top item. Value range between :0-1
.region
is a Bounding box. It represents the location and the size of the object in the sent image.
It may happen that our service can't recognize or match an image. This is why we provide you a service to notify us about the unrecognized image.
Before you mark an image as not found, you will need to extract the requestId
.
nyris
.imageMatching()
.match<OfferResponse>(imageByteArray)
.subscribe({/* it:OfferResponse */
// Handle your response
requestId = it.requestId
},{/* it:Throwable */
...
})
After getting the requestId
you can mark the image as not found.
nyris
.notFoundMatching()
.markAsNotFound(requestId)
.subscribe({/* it:ResponseBody */
...
},{/* it:Throwable */
...
})
nyris offers a service that helps you to search offers by text, SKU, barcode, etc.
you can use the text search service the same way as image matching service
nyris
.textSearch()
.searchOffers("YOUR_TEXT")
.subscribe({/*it:OfferResponseBody*/
// Handle your response
val offers = it.offers
},{/* it:Throwable */
...
})
nyris
.textSearch()
.outputFormat("PROVIDED_OUTPUT_FORMAT") // Set the desired OUTPUT_FORMAT
.language("de") // Return only offer with language "de"
.regroup({ //[DEPRECATED]
enabled = true // This mode enables regrouping of the items
threshold = 0.5F // The lower limit of confidences for the regroup
})
.limit(10) // Limit returned offers
.searchOffers<JsonResponseBody>("YOUR_TEXT", JsonResponseBody::class.java)
.subscribe({/* it:JsonResponseBody */
//Handle your response
val json = it.json
},{/* it:Throwable */
...
})
Before you send a feedback event, you will need to get the requestId
and the sessionId
.
nyris
.imageMatching()
.match<OfferResponse>(imageByteArray)
.subscribe({/* it:OfferResponse */
// Handle your response
requestId = it.requestId
sessionId = it.sessionId
},{/* it:Throwable */
...
})
nyris
.feedback()
.send(
Event.Click(
requestId = "REQUEST_ID",
sessionId = "SESSION_ID",
poductIds = listof("1","2","3"), //A list of string values, containing the Product IDs
position = listof(0,2) // A list of int values describing the zero-based index of the result returned by our Find API.
)
)
.subscribe({}, {}) //Completable
nyris
.feedback()
.send(
Event.Conversion(
requestId = "REQUEST_ID",
sessionId = "SESSION_ID",
poductIds = listof("1","2","3"), //A list of string values, containing the Product IDs
position = listof(0,2) // A list of int values describing the zero-based index of the result returned by our Find API.
)
)
.subscribe({}, {}) //Completable
nyris
.feedback()
.send(
Event.Feedback(
requestId = "REQUEST_ID",
sessionId = "SESSION_ID",
success = true, //A boolean resembling general business success of a result.
comment = "a comment" // An optional string containing verbatim user feedback.
)
)
.subscribe({}, {}) //Completable
nyris
.feedback()
.send(
Event.Region(
requestId = "REQUEST_ID",
sessionId = "SESSION_ID",
lefy = 1, // The left coordinate of the region as a fraction of the image width (range 0..1 ).
top = 1, // The top coordinate of the region as a fraction of the image height (range 0..1 ).
width = 1, // The width of the region as a fraction of the image width (range 0..1 ).
height = 1 // The height of the region as a fraction of the image height (range 0..1 ).
)
)
.subscribe({}, {}) //Completable
Search options is a way to filter the results on the backend side. To search with filters you need to:
nyris
.imageMatching()
.filters {
list = listOf(
Filter(filterType = "YOUR_FILTER_TYPE_1", listOf("YOUR_FILTER_VALUE_1", "YOUR_FILTER_VALUE_2")),
Filter(filterType = "YOUR_FILTER_TYPE_2", listOf("YOUR_FILTER_VALUE_1", "YOUR_FILTER_VALUE_2")),
)
}
.match(byteArray)
.subscribe({}, {})
We will process the image with provided filters and return a JSON object containing the metadata of the identified items. The returned items will have the provided filter types and values.
Copyright 2018 nyris GmbH
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.