Cropper
What is Cropper?
Cropper enables users to retrieve the coordinates of cropped images from a document through our APIs.
Cropper can be used in two ways:
- On any API by adding an additional parameter.
- By using the stand alone API Cropper.
How it Works
The cropper feature can be used on any API on the prediction route:
https://api.mindee.net/v1/products/<account_name>/<api_name>/<api_version>/predict?cropper=true
?cropper=true
is the additional parameter to add to your API calls.
Cropper Output
The cropper results are located at the page level when retrieving document prediction. The cropper results are returned in the following JSON object document.inference.pages[].extras.cropper.cropping[].xxxxxx
. Most of the time, taking the first element of the cropper output is sufficient for most use case.
The results show the polygon vertices at the page level, for each possible cropped document within the image:
- bounding_box: straight rectangle (always inside canvas).
- rectangle: rectangle that may be oriented (can go beyond the canvas, ie. vertices coordinate < 0 and > 1).
- quadrangle: free polygon with 4 vertices (always inside canvas).
- polygon: free polygon with up to 30 vertices (always inside canvas).
The vertices format are a list of (x, y) relative coordinates to your document, always in clockwise order. Starting vertex may not be fixed (depends if this is a rectangle or a free polygon).
Example:
...
"rectangle": [
[0, 0.996],
[0.002, -0.002],
[0.996, 0],
[0.994, 0.998]
]
...
Orientation
The coordinates returned by the cropper take in consideration the rotation of the document. You can find this information in
document.inference.pages[].orientation
in the form of clockwise degrees. The value is the clockwise rotation to apply on the source page document to get the page upright.
Example With Receipts V5
Using this sample receipt document we append the cropper additional param ?cropper=true
to the receipts API URL.
curl -X POST
https://api.mindee.net/v1/products/mindee/expense_receipts/v5/predict?cropper=true
-H 'Authorization: Token my-token'
-F document=@/path/to/your/file.png
import requests
url = "https://api.mindee.net/v1/products/mindee/expense_receipts/v3/predict?cropper=true"
with open("/path/to/my/file", "rb") as myfile:
files = {"document": myfile}
headers = {"Authorization": "Token my-api-key-here"}
response = requests.post(url, files=files, headers=headers)
print(response.text)
// works for NODE > v10
const axios = require('axios');
const fs = require("fs");
const FormData = require('form-data')
async function makeRequest() {
let data = new FormData()
data.append('document', fs.createReadStream('./file.jpg'))
const config = {
method: 'POST',
url: 'https://api.mindee.net/v1/products/mindee/expense_receipts/v3/predict?cropper=true',
headers: {
'Authorization':'Token my-api-key-here',
...data.getHeaders()
},
data
}
try {
let response = await axios(config)
console.log(response.data);
} catch (error) {
console.log(error)
}
}
makeRequest()
# tested with Ruby 2.5
require 'uri'
require 'net/http'
require 'net/https'
require 'mime/types'
url = URI("https://api.mindee.net/v1/products/mindee/expense_receipts/v3/predict?cropper=true")
file = "/path/to/your/file.png"
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Token my-api-key-here'
request.set_form([['document', File.open(file)]], 'multipart/form-data')
response = http.request(request)
puts response.read_body
<form onsubmit="mindeeSubmit(event)" >
<input type="file" id="my-file-input" name="file" />
<input type="submit" />
</form>
<script type="text/javascript">
const mindeeSubmit = (evt) => {
evt.preventDefault()
let myFileInput = document.getElementById('my-file-input');
let myFile = myFileInput.files[0]
if (!myFile) { return }
let data = new FormData();
data.append("document", myFile, myFile.name);
let xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://api.mindee.net/v1/products/mindee/expense_receipts/v3/predict?cropper=true");
xhr.setRequestHeader("Authorization", "Token my-api-key-here");
xhr.send(data);
}
</script>
Our result shows the different polygon vertices (bounding_box
, rectangle
, quadrangle
, polygon
) at the page level.
{
...
"document": {
"id": "62c6198c-e0a8-4ee7-b922-7b5b98bedb79",
"inference": {
"extras": {},
"finished_at": "2022-03-25T16:17:18+00:00",
"is_rotation_applied": true,
"pages": [
{
"extras": {
"cropper": {
"cropping": [
{
"bounding_box": [
[0.121, 0],
[0.787, 0],
[0.787, 0.998],
[0.121, 0.998]
],
"polygon": [
[0.152, 0.416],
[0.16, 0.186],
[0.172, 0.02],
[0.211, 0.006],
[0.357, 0.006],
[0.592, 0.006],
[0.656, 0.023],
[0.775, 0.043],
[0.789, 0.055],
[0.756, 0.549],
[0.756, 0.637],
[0.736, 0.955],
[0.719, 0.994],
[0.607, 0.996],
[0.197, 0.996],
[0.131, 0.994],
[0.123, 0.982],
[0.125, 0.855],
[0.139, 0.668],
[0.139, 0.584]
],
"quadrangle": [
[0.173, 0],
[0.786, 0.012],
[0.737, 0.994],
[0.122, 0.996]
],
"rectangle": [
[0.172, -0.019],
[0.785, 0.012],
[0.735, 1.027],
[0.121, 0.996]
]
}
]
}
},
"id": 0,
"orientation": {
"value": 0
},
...
}
]
}
}
}
Cropper standalone API
Setup the API
- Access your Cropper API by clicking on the Cropper card in the Utilities tab:
- From the left navigation, go to documentation > API Reference, you'll find sample code in popular languages and command line.
from mindee import Client, PredictResponse, product
# Init a new client
mindee_client = Client(api_key="my-api-key-here")
# Load a file from disk
input_doc = mindee_client.source_from_path("/path/to/the/file.ext")
# Load a file from disk and parse it.
# The endpoint name must be specified since it cannot be determined from the class.
result: PredictResponse = mindee_client.parse(product.CropperV1, input_doc)
# Print a summary of the API result
print(result.document)
# Print the document-level summary
# print(result.document.inference.prediction)
const mindee = require("mindee");
// for TS or modules:
// import * as mindee from "mindee";
// Init a new client
const mindeeClient = new mindee.Client({ apiKey: "my-api-key-here" });
// Load a file from disk
const inputSource = mindeeClient.docFromPath("/path/to/the/file.ext");
// Parse the file
const apiResponse = mindeeClient.parse(
mindee.product.CropperV1,
inputSource
);
// Handle the response Promise
apiResponse.then((resp) => {
// print a string summary
console.log(resp.document.toString());
});
using Mindee;
using Mindee.Input;
using Mindee.Product.Cropper;
string apiKey = "my-api-key-here";
string filePath = "/path/to/the/file.ext";
// Construct a new client
MindeeClient mindeeClient = new MindeeClient(apiKey);
// Load an input source as a path string
// Other input types can be used, as mentioned in the docs
var inputSource = new LocalInputSource(filePath);
// Call the API and parse the input
var response = await mindeeClient
.ParseAsync<CropperV1>(inputSource);
// Print a summary of all the predictions
System.Console.WriteLine(response.Document.ToString());
using Mindee;
using Mindee.Input;
using Mindee.Product.Cropper;
string apiKey = "my-api-key-here";
string filePath = "/path/to/the/file.ext";
// Construct a new client
MindeeClient mindeeClient = new MindeeClient(apiKey);
// Load an input source as a path string
// Other input types can be used, as mentioned in the docs
var inputSource = new LocalInputSource(filePath);
// Call the API and parse the input
var response = await mindeeClient
.ParseAsync<CropperV1>(inputSource);
// Print a summary of all the predictions
System.Console.WriteLine(response.Document.ToString());
import com.mindee.MindeeClient;
import com.mindee.input.LocalInputSource;
import com.mindee.parsing.common.PredictResponse;
import com.mindee.product.cropper.CropperV1;
import java.io.File;
import java.io.IOException;
public class SimpleMindeeClient {
public static void main(String[] args) throws IOException {
String apiKey = "my-api-key-here";
String filePath = "/path/to/the/file.ext";
// Init a new client
MindeeClient mindeeClient = new MindeeClient(apiKey);
// Load a file from disk
LocalInputSource inputSource = new LocalInputSource(filePath);
// Parse the file
PredictResponse<CropperV1> response = mindeeClient.parse(
CropperV1.class,
inputSource
);
// Print a summary of the response
System.out.println(response.toString());
// Print a summary of the predictions
// System.out.println(response.getDocument().toString());
// Print the page-level predictions
// response.getDocument().getInference().getPages().forEach(
// page -> System.out.println(page.toString())
// );
}
}
<form onsubmit="mindeeSubmit(event)" >
<input type="file" id="my-file-input" name="file" />
<input type="submit" />
</form>
<script type="text/javascript">
const mindeeSubmit = (evt) => {
evt.preventDefault()
let myFileInput = document.getElementById('my-file-input');
let myFile = myFileInput.files[0]
if (!myFile) { return }
let data = new FormData();
data.append("document", myFile, myFile.name);
let xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://api.mindee.net/v1/products/mindee/cropper/v1/predict");
xhr.setRequestHeader("Authorization", "Token my-api-key-here");
xhr.send(data);
}
</script>
curl -X POST \\
https://api.mindee.net/v1/products/mindee/cropper/v1/predict \\
-H 'Authorization: Token my-api-key-here' \\
-H 'content-type: multipart/form-data' \\
-F document=@/path/to/your/file.png
<?php
use Mindee\Client;
use Mindee\Product\Cropper\CropperV1;
// Init a new client
$mindeeClient = new Client("my-api-key-here");
// Load a file from disk
$inputSource = $mindeeClient->sourceFromPath("/path/to/the/file.ext");
// Parse the file
$apiResponse = $mindeeClient->parse(CropperV1::class, $inputSource);
echo $apiResponse->document;
- Replace my-api-key-here with your new API key, or use the "select an API key" feature and it will be filled automatically.
- Copy and paste the sample code of your desired choice in your application, code environment or terminal.
- Replace
/path/to/my/file
with the path to your document.
Always remember to replace your API key!
- Run your code. You will receive a JSON response with the position details .
API Response
Here is the full JSON response you get when you call the API:
{
"extras": {},
"finished_at": "2023-04-18T14:15:13.557525",
"is_rotation_applied": null,
"pages": [
{
"extras": {},
"id": 0,
"orientation": {
"value": null
},
"prediction": {
"cropping": [
{
"bounding_box": [
[
0.547,
0.096
],
[
0.883,
0.096
],
[
0.883,
0.977
],
[
0.547,
0.977
]
],
"polygon": [
[
0.605,
0.332
],
[
0.613,
0.188
],
[
0.645,
0.15
],
[
0.672,
0.168
],
[
0.686,
0.107
],
[
0.697,
0.107
],
[
0.701,
0.152
],
[
0.73,
0.182
],
[
0.746,
0.123
],
[
0.752,
0.125
],
[
0.766,
0.166
],
[
0.791,
0.152
],
[
0.869,
0.158
],
[
0.871,
0.234
],
[
0.859,
0.277
],
[
0.859,
0.402
],
[
0.836,
0.658
],
[
0.805,
0.955
],
[
0.701,
0.947
],
[
0.674,
0.932
],
[
0.582,
0.908
],
[
0.562,
0.885
],
[
0.568,
0.654
],
[
0.594,
0.514
],
[
0.596,
0.445
],
[
0.609,
0.406
]
],
"quadrangle": [
[
0.625,
0.096
],
[
0.882,
0.157
],
[
0.803,
0.975
],
[
0.549,
0.9
]
],
"rectangle": [
[
0.625,
0.096
],
[
0.886,
0.121
],
[
0.803,
0.975
],
[
0.542,
0.949
]
]
},
{
"bounding_box": [
[
0.195,
0
],
[
0.482,
0
],
[
0.482,
0.988
],
[
0.195,
0.988
]
],
"polygon": [
[
0.201,
0.439
],
[
0.191,
0.281
],
[
0.197,
0.291
],
[
0.191,
0.117
],
[
0.197,
0.041
],
[
0.254,
0.037
],
[
0.33,
0.006
],
[
0.436,
0.006
],
[
0.467,
0.301
],
[
0.467,
0.4
],
[
0.475,
0.473
],
[
0.467,
0.562
],
[
0.477,
0.584
],
[
0.467,
0.674
],
[
0.48,
0.779
],
[
0.457,
0.965
],
[
0.334,
0.973
],
[
0.277,
0.986
],
[
0.213,
0.986
],
[
0.215,
0.797
],
[
0.186,
0.793
],
[
0.197,
0.744
],
[
0.193,
0.689
],
[
0.211,
0.629
],
[
0.197,
0.576
]
],
"quadrangle": [
[
0.197,
0.019
],
[
0.456,
0
],
[
0.481,
0.963
],
[
0.197,
0.988
]
],
"rectangle": [
[
0.169,
0.008
],
[
0.455,
0
],
[
0.481,
0.979
],
[
0.195,
0.986
]
]
}
]
}
}
],
"prediction": {},
"processing_time": 0.519,
"product": {
"features": [
"cropping"
],
"name": "mindee/cropper",
"type": "standard",
"version": "1.0"
},
"started_at": "2023-04-18T14:15:13.038768"
}
Questions?
Join our Slack
Updated about 2 months ago