Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Example of a request

Code Block
languagepy
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:

Code Block
languagepy
from pathlib import Path

image = Path("{image_path}").read_bytes()

...

Example of a code sending an image for analyzing using the analyze_image command:

Code Block
languagepy
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,
        )

...

You also have to send the numpy array as byte stream which you can do like this:

Code Block
languagepy
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
languagepy
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
languagepy
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,
        )

...

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
languagepy
url = f"http://{self.ip}:{self.port}/ping"

To check whether a server is running you can use this code:

Code Block
languagepy
import requests

url = f"http://{self.ip}:{self.port}/ping"
try:
    response = requests.get(url=url, timeout=5)
    print("server is running")
except requests.exceptions.Timeout as e:
    print("server is offline")

...

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
languagepy
import requests

url = f"http://{self.hostip}:{self.port}/stop"
requests.get(url=url, timeout=5)

...

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.

Parsing response from request

In case the request you sent is supposed to return some response (as is the case for the POST request and with some types of commands for GET request) you will have to parse the response from bytes to usable data. The parsing required varies based on the request

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 InputHost 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
languagepy
'http://127.0.0.1:8000/analyze_image?data=SomeInfo'

In the Code module, you can access this string using:

Code Block
languagepy
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
languagepy
'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
languagepy
'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:

Code Block
breakoutModewide
languagepy
import cv2
import requests

cap = cv2.VideoCapture(0)

# you can set frame size
# cap.set(cv2.CAP_PROP_FRAME_WIDTH, 960)
# cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 540)

# keep alive
request_session = requests.Session()

while True:
    # get frame from camera
    ret, frame = cap.read()

    # get image shape
    shape = frame.shape

    # send frame to PEKAT VISION
    response = requests.post(
        url='http://127.0.0.1:8000/analyze_raw_image?width='+str(shape[1])+'&height='+str(shape[0]),
        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
languagepy
'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
breakoutModewide
languagepy
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:{port}/last_image?response_type=annotated_image',
    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
languagepy
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
languagepy
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
languagepy
from PIL import Image
from io import BytesIO

img = Image.open(BytesIO(response.content))
img.show()

Example of decoding and showing the image with OpenCV library:

Code Block
languagepy
import cv2
import numpy 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).

For all those image response types, the serialized context is by default added to the headers with the header title 'ContextBase64utf'. To get it to JSON form, you can use this code:

Code Block
languagepy
import 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:

...

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
languagepy
import requests

url = f"http://{ip}:{port}/last_image?response_type={response_type}"
response = requests.get(
    url=url,
    headers={'Content-Type': 'application/octet-stream'}
)

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
languagepy
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
languagepy
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
languagepy
import json

response = {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
languagepy
import json

context_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):

...