...
Example of a request
Code Block | ||
---|---|---|
| ||
import requests
url = f"http://{ip}:{port}/{command}&{required_arguments}&{optional_arguments}"
response = requests.post(
url,
data=image,
headers={"Content-Type": "application/octet-stream"},
timeout=timeout,
) |
...
URL arguments provide additional context to PEKAT, either required or optional and they differ based on the request and command.
Request Arguments
The arguments sent in the request are always
POST request
Post request is used to send images for analyzing to PEKAT project and get result. A general POST request to PEKAT project would look like this:
Code Block | ||
---|---|---|
| ||
import requests
url = f"http://{ip}:{port}/{command}&{required_arguments}&{optional_arguments}"
response = requests.post(
url,
data=image,
headers={"Content-Type": "application/octet-stream"},
timeout=timeout,
) |
...
Info | |||||
---|---|---|---|---|---|
It’s recommended to load the .png image data using the Path class from pathlib and simply use the .read_bytes() method like this:
|
...
Example of a code sending an image for analyzing using the analyze_image command:
Code Block | ||
---|---|---|
| ||
from pathlib import Path
import requests
image = Path("img.png").read_bytes()
url = f"http://127.0.0.1:8000/analyze_image"
response = requests.post(
url,
data=image,
headers={"Content-Type": "application/octet-stream"},
timeout=5,
) |
...
Info | |||||
---|---|---|---|---|---|
For testing, you can also generate random numpy array that could represent an image (in this example, the image size is 512x512 and it’s an rgb image) like this:
|
Additional arguments
The additional arguments
Warning |
---|
Continue from here |
The sending address consists of the IP address, port, type, and optional further query parameters. The request method must be of ‘POST’ type and the content type of ‘application/octet-stream’ type.
Find a practical API demonstration in Python at
...
IP Address
If the project runs on a local computer, the address is 127.0.0.1. If a remote computer is accessed, then you need to use the IP address of the remote computer.
It is necessary to specify the IP address of the PC that is going to send the images. To do this navigate to Input → Host panel and modify the IP address.
...
Port
This is selected when starting the project, the default is 8000.
Data
You can add extra information to the request. This string will be added to the context (the key is data). It is available only in the Code module (context variable).
Code Block | ||
---|---|---|
| ||
'http://127.0.0.1:8000/analyze_image?data=SomeInfo' |
In the Code module, you can access this string using:
Code Block | ||
---|---|---|
| ||
context['data'] |
Types
analyze_raw_image
Used for sending the image as raw data. For example, the NumPy array in Python is converted to binary format.
You need to send the image dimensions in query parameters width and height.
Example of a 1920x1024 image:
Code Block | ||
---|---|---|
| ||
'http://127.0.0.1:8000/analyze_raw_image?width=1920&height=1024' |
If you are sending Bayer RG 8 data, it is necessary to add an argument bayer.
Code Block | ||
---|---|---|
| ||
'http://127.0.0.1:8000/analyze_raw_image?width=1920&height=1024&bayer' |
Example of a Python code sending requests with raw images from the camera:
...
breakoutMode | wide |
---|---|
language | py |
...
You also have to send the numpy array as byte stream which you can do like this:
Code Block | ||
---|---|---|
| ||
image_bytes = image.tobytes() |
Finally, if the image is in the Bayer RG format, you also need to specify this in the URL like this:
Code Block | ||
---|---|---|
| ||
url = f"http://127.0.0.1:8000/analyze_raw_image?height={height}&width={width}&bayer" |
Example of a full analyze_raw_image request would look like this:
Code Block | ||
---|---|---|
| ||
from pathlib import Path
import cv2
import requests
image = cv2.imread({"image_path"})
height, width = image.shape[:2]
url = f"http://127.0.0.1:8000/analyze_raw_image?height={height}&width={width}"
response = requests.post(
url,
data=image.tobytes(),
headers={"Content-Type": "application/octet-stream"},
timeout=5,
) |
Additional optional arguments
The additional optional arguments that can be send in the URL of the request can be:
response_type - specifies the response type that is to be returned from the project, meaning what information it should contain
data - additional data to be send to project as a string that the project can use to separate the images in different flows and other things
context_in_body - the context of the analysis will be returned in the body of the response, meaning that the response will need to be parsed in a different way
Response type
Response type can be either:
context - the response will only contain context resulting from the analysis - this is the default response type
image - the response will contain processed image (without rectangles or heatmaps but with the changes from preprocess module)
annotated_image - the response will contain processed image with detected rectangles from all active modules
heatmap - response will contain layered heatmaps on the processed image
An example of a full POST request
Full analyze_raw_image POST request with all optional arguments would look like this:
Code Block | ||
---|---|---|
| ||
from pathlib import Path import cv2 import requests image = cv2.imread({"image_path"}) height, width = image.shape[:2] url = f"http://127.0.0.1:8000/analyze_raw_image?response_type=image&height={height}&width={width}&data={project_data}" response = requests.post( url, data=image.tobytes(), headers={"Content-Type": "application/octet-stream"}, url='http://127.0.0.1:8000/analyze_raw_image?width='+str(shape[1])+'&height='+str(shape[0])timeout=5, data=frame.tobytes(), headers={'Content-Type': 'application/octet-stream'} ) print(response.json()) |
analyze_image
Is used for sending an image in ‘jpg’ or ‘png’ formats.
Basic example
Code Block | ||
---|---|---|
| ||
'http://127.0.0.1:8000/analyze_image' |
Example Python code that sends images from a folder to the Pekat project with an API key:
Code Block | ||||
---|---|---|---|---|
| ||||
import requests
import os
request_session = requests.Session()
for image in os.listdir('images_folder'):
with open(os.path.join('images_folder', image), 'rb') as image:
response = requests.post(
url='http://127.0.0.1:8000/analyze_image?api_key=728a9180-8357-11ec-b645-e917eb5f5d27',
data=image.read(),
headers={'Content-Type': 'application/octet-stream'}
)
print(response.json()) |
last_image
...
Code Block |
---|
http://127.0.0.1:8000/last_image |
Python code which gets the last processed image with heatmap and shows it then prints out the context.
Code Block |
---|
import requests import cv2 import numpy as np import base64 import json port = '8000' request_session = requests.Session() response = requests.get( url=f'http://127.0.0.1) |
The response returns byte data so to be able to use it in a meaningful way, you will first need to parse it into a usable data type.
GET request
Get request has 3 different types of commands and each is filling a different role. The commands available are:
ping - check if a project is running
stop - stop a project
last_image - get last analyzed image from a project
ping
This is a simple command that you can use to check whether the project is running or not. The URL of this command doesn’t take any additional arguments and it looks like this:
Code Block | ||
---|---|---|
| ||
url = f"http://{ip}:{port}/ping" |
To check whether a server is running you can use this code:
Code Block | ||
---|---|---|
| ||
import requests
url = f"http://{ip}:{port}/ping"
try:
response = requests.get(url=url, timeout=5)
print("server is running")
except requests.exceptions.Timeout as e:
print("server is offline")
|
stop
This is another simple command that can be used to stop a running PEKAT project, however it is recommended to use it only if you start PEKAT project as a process in your script. The code for this command would look like this:
Code Block | ||
---|---|---|
| ||
import requests
url = f"http://{ip}:{port}/stop"
requests.get(url=url, timeout=5) |
last_image
You can use this command to get the last analyzed image from a running project. This can perhaps be useful when you’re sending images to a project from one script and then check the results in another one.
With this get request, you can also specify the response_type and you’ll also need to parse the result.
The request would look like this:
Code Block | ||
---|---|---|
| ||
import requests url = f"http://{ip}:{port}/last_image?response_type=annotated_image'{response_type}" response = requests.get( url=url, headers={'Content-Type': 'application/octet-stream'} ) # Decode and show image with heatmap img = cv2.imdecode(np.frombuffer(response.content, np.uint8), 1) cv2.imshow("Image", img) cv2.waitKey(0) # Decode context from Base64 context_str = base64.b64decode(response.headers['ContextBase64utf']) # Load json from string context = json.loads(context_str) print(context) |
Response type
Query parameter ‘response_type’ determines what content will be sent in the response that is returned from PEKAT VISION after processing the request. The request URL changes in the following way (example for annotated_image response type):
Code Block | ||
---|---|---|
| ||
response = requests.post(
url='http://127.0.0.1:8000/analyze_image?response_type=annotated_image',
data=image.read(),
headers={'Content-Type': 'application/octet-stream'}
) |
Context
context – a serialized context in JSON format. The contents are explained on the Context page. You can access the context json from the response using:
Code Block | ||
---|---|---|
| ||
j = response.json() |
Images
Further options return a PNG image in binary form in the response. It needs to be decoded afterward to further work with it as an image.
Example of decoding and showing the image with the PIL library:
Code Block | ||
---|---|---|
| ||
from PIL import Image
from io import BytesIO
img = Image.open(BytesIO(response.content))
img.show() |
...
Parsing response from request
In case the request you sent is supposed to return some data in the response (as is the case for the POST request and with last_image command for GET request) you will have to parse the response from bytes to usable data. The parsing required varies somewhat based on the request response_type and whether you had set the “context_in_body” optional argument set.
The simplest option is when you had the response_type set to “context”, because you can just read the .json data from the response:
Code Block | ||
---|---|---|
| ||
import json
response = {your_request}
context = response.json() |
If you DON’T have “context_in_body” set in the URL, the image and the context will be sent in the separate parts of the response. Image in the content of the response and context in “ContextBase64utg” attribute of the response. If that attribute is None it means that no image was sent back and you can access the context just like when the response type is set to “context”.
Code Block | ||
---|---|---|
| ||
import json
response = {your_request}
img_bytes = response.content
context_base64 = response.headers.get("ContextBase64utf")
if context_base64 is None:
return Result(None, response.json())
context_json = base64.b64decode(context_base64)
context = json.loads(context_json) |
If you DO have “context_in_body” set in the URL, the image and the context will be sent together and you’ll have to split them apart. You can do this by accessing the “ImageLen“ attribute of the response - it tells you how much of the data is the image (the first part) the rest is context. If ImageLen is None, no image was sent and again, you can just parse the context like when the response type is just “context”.
Code Block | ||
---|---|---|
| ||
import cv2json import numpyresponse as np img = cv2.imdecode(np.frombuffer(response.content, np.uint8), 1) cv2.imshow("Image", img) cv2.waitKey(0) |
image – processed image - output image that passed through the flow, but without any heatmaps or rectangles (e.g. if the image is scaled during the flow, it returns a scaled image).
annotated_image – processed image with annotations - heatmaps over the image.
heatmap - response contains only the heatmaps over the image (without the image).
...
= {your_request}
image_len_str = response.headers.get("ImageLen")
if not image_len_str:
return Result(None, response.json())
image_len = int(image_len_str)
img_bytes = response.content[:image_len]
context_json = response.content[image_len:].decode()
context = json.loads(context_json) |
Finally, you can combine all of the options of parsing into one code if you want:
Code Block | ||
---|---|---|
| ||
import json base64 import json # Decode from Base64 context_str = base64.b64decode(response.headers['ContextBase64utf']) # Load json from string context = json.loads(context_str) |
Context in body
When getting an image in the response, by default the context is sent in headers. However, with a very large number of defects, the maximum header length limit can be reached. To solve this, you can use the option to send context in the body of the response together with the image and get the image length in a header 'ImageLen' to be able to divide the two parts after. To activate this mode, add the following to the request:
Code Block |
---|
context_in_body=t |
Example of the usage in Python code when getting the last image:
Code Block |
---|
import requests import cv2 import numpy as np import json port = '8000' request_session = requests.Session() response = requests.get( url=f'http://127.0.0.1:{port}/last_image?response_type=annotated_image&context_in_body=t', headers={'Content-Type': 'application/octet-stream'} ) # Get image length img_len = int(response.headers['ImageLen']) # Decode and show image with heatmap img = cv2.imdecode(np.frombuffer(response.content[:img_len], np.uint8), 1) cv2.imshow("Image", img) cv2.waitKey(0) # Get and print context context = json.loads(response.content[img_len:]) print(contextcontext_in_body = {your_option} # either True or False response_type = {your_response_type} response = {your_request} if response_type == "context": None, response.json() if context_in_body: image_len_str = response.headers.get("ImageLen") if not image_len_str: return Result(None, response.json()) image_len = int(image_len_str) img_bytes = response.content[:image_len] context_json = response.content[image_len:].decode() else: img_bytes = response.content context_base64 = response.headers.get("ContextBase64utf") if context_base64 is None: return Result(None, response.json()) context_json = base64.b64decode(context_base64) return img_bytes, json.loads(context_json) |
Testing the API functionality
If you have a running project on a port e.g. 8000, you can test the API by accessing this address in your browser (if PEKAT is running on the local computer, otherwise replace localhost with the IP address of the remote PC):
...