Author Topic: Seek Compact Pro python script?  (Read 8732 times)

0 Members and 1 Guest are viewing this topic.

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Seek Compact Pro python script?
« on: June 23, 2018, 07:48:36 am »
Hi there

Is there perhaps someone who has a ready to use python script for talking to the
Seek Compact Pro? I just want to output the raw frames, I dont care on palettes nor
other fancy after effects. There is already such a script for the normal Compact as I found here
but it seems its is alot different for the initialisation part and image dimension...

If not I will try to start step by step converting it here, maybe someone can help me with the stuff I dont understand..


« Last Edit: June 23, 2018, 07:59:25 am by pauledd »
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #1 on: June 24, 2018, 07:55:07 am »
Okay, I just start with the usb stuff and the initialisation routine.
for the send/receive order I follow the code used in libseek-thermal (SeekThermalPro.cpp):

Code: [Select]
import usb.core
import usb.util

#find Seek CompactPro device 289d:0011
dev = usb.core.find(idVendor=0x289d, idProduct=0x0011)
if not dev: raise ValueError('Device not found')

def send_msg(bmRequestType, bRequest, wValue=0, wIndex=0, data_or_wLength=None, timeout=None):
    assert (dev.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout) == len(data$

# alias method to make code easier to read
receive_msg = dev.ctrl_transfer

def deinit():
    '''Deinit the device'''
    msg = '\x00\x00'
    for i in range(3):
        send_msg(0x41, 0x3C, 0, 0, msg)

# set the active configuration. With no arguments, the first configuration will be the active one
dev.set_configuration()

# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]

custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT
ep = usb.util.find_descriptor(intf, custom_match=custom_match)   # match the first OUT endpoint
assert ep is not None


# Setup device
try:
    msg = '\x01'
    send_msg(0x41, 0x54, 0, 0, msg)
    print "Setup try"
except Exception as e:
    deinit()
    msg = '\x01'
    send_msg(0x41, 0x54, 0, 0, msg)
    print "Setup except"


# SET_OPERATION_MODE = 60; 0x41=send,0x3C=60
send_msg(0x41, 0x3C, 0, 0, '\x00\x00')

# GET_FIRMWARE_INFO = 78, 0x4E=78
ret1 = receive_msg(0xC1, 0x4E, 0, 0, 4)
print "GET_FIRMWARE_INFO=",ret1

# READ_CHIP_ID = 54, 0x36=54
ret2 = receive_msg(0xC1, 0x36, 0, 0, 12)
print "READ_CHIP_ID=",ret2

# SET_FACTORY_SETTINGS_FEATURES = 86 = 0x56
send_msg(0x41, 0x56, 0, 0, '\x06\x00\x08\x00\x00\x00')

# GET_FACTORY_SETTINGS = 88 = 0x58
ret3 = receive_msg(0xC1, 0x58, 0, 0, 12)
print "GET_FACTORY_SETTINGS=",ret3

# SET_FIRMWARE_INFO_FEATURES = 85 = 0x55
send_msg(0x41, 0x55, 0, 0, '\x17\x00')

# GET_FIRMWARE_INFO = 78 = 0x4E
ret4 = receive_msg(0xC1, 0x4E, 0, 0, 64)
print "GET_FIRMWARE_INFO=",ret4

# SET_FACTORY_SETTINGS_FEATURES = 86 = 0x56
send_msg(0x41, 0x56, 0, 0, '\x01\x00\x00\x06\x00\x00')

# GET_FACTORY_SETTINGS
ret5 = receive_msg(0xC1, 0x58, 0, 0, 2)
print "GET_FACTORY_SETTINGS=",ret5

# SET_FACTORY_SETTINGS_FEATURES = 86 = 0x56
send_msg(0x41, 0x56, 0, 0, '\x01\x00\x01\x06\x00\x00')

# GET_FACTORY_SETTINGS
ret6 = receive_msg(0xC1, 0x58, 0, 0, 2)
print "GET_FACTORY_SETTINGS=",ret6

This, so far outputs this and seems to work:

Code: [Select]
Setup try
GET_FIRMWARE_INFO= array('B', [1, 0, 3, 0])
READ_CHIP_ID= array('B', [6, 0, 16, 0, 141, 0, 211, 0, 93, 0, 209, 0])
GET_FACTORY_SETTINGS= array('B', [48, 54, 49, 48, 65, 49, 74, 85, 76, 68, 53, 52])
GET_FIRMWARE_INFO= array('B', [48, 120, 68, 49, 53, 68, 68, 51, 56, 68, 49, 48, 48, 54, 0, 0, 48, 54, 49, 48 65, 49, 74, 85, 76, 68, 53, 52, 0, 0, 0, 0, 121, 5, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
GET_FACTORY_SETTINGS= array('B', [0, 0])
GET_FACTORY_SETTINGS= array('B', [1, 0])

Next part will be to Send read frame request...

In libseek-thermal this code comes next, which I dont fully understand yet:
Code: [Select]
uint16_t addr, addrle;
    uint8_t *addrle_p = reinterpret_cast<uint8_t*>(&addrle);

    for (addr=0; addr<2560; addr+=32) {
        {
            addrle = htole16(addr); /* mind endianness */
            std::vector<uint8_t> data = { 0x20, 0x00, addrle_p[0], addrle_p[1], 0x00, 0x00 };
            if (!m_dev.request_set(DeviceCommand::SET_FACTORY_SETTINGS_FEATURES, data))
                return false;
        }
        {
            std::vector<uint8_t> data(64);
            if (!m_dev.request_get(DeviceCommand::GET_FACTORY_SETTINGS, data))
                return false;
            print_usb_data(data);
        }
}
« Last Edit: June 24, 2018, 08:05:58 am by pauledd »
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #2 on: June 24, 2018, 08:23:25 am »
obviously it loopes 2560 times in 32 step size, which should be 80 times, while
sending SET_FACTORY_SETTINGS_FEATURES requests with custom addrle_p[0], addrle_p[1] things that have to do with little endian...  ??? lets see if one can translate that somehow to python
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #3 on: June 24, 2018, 09:41:34 am »
If my understanding is correct addr, addrle are unsigned int 0-65536. addrle is the little endian value
of addr, which is possibly can be made by this snipped of code:

Code: [Select]
addrle = '\\x' + '\\x'.join(x.encode('hex') for x in struct.pack('<I', addr))
Then addrle is c++ reinterpret-casted from uint16 to uint8?  ???

Code: [Select]
uint8_t *addrle_p = reinterpret_cast<uint8_t*>(&addrle);
Currently dont know how to do that in python...
human being - without Windows® - excuse my bad english
 

Offline tonykids

  • Regular Contributor
  • *
  • Posts: 79
Re: Seek Compact Pro python script?
« Reply #4 on: June 24, 2018, 10:33:51 am »
Do not think that too much,it's simple :)
Just loop the "m_dev.request_set(DeviceCommand::SET_FACTORY_SETTINGS_FEATURES, data)" 80 times
and for each time the data byte array is
20 ,00 ,00 ,00 ,00 ,00<--the first time
20 ,00 ,20 ,00 ,00 ,00<--the second time
20 ,00 ,40 ,00 ,00 ,00
.
.
20 ,00 ,e0 ,00 ,00 ,00
20 ,00 ,00 ,01 ,00 ,00
20 ,00 ,20 ,01 ,00 ,00
.
.
.
20 ,00 ,c0 ,09 ,00 ,00
20 ,00 ,e0 ,09 ,00 ,00
<--the last time

Seehttps://www.eevblog.com/forum/thermal-imaging/windows-software-for-seek-pro-and-initial-commands/for more information
« Last Edit: June 24, 2018, 10:38:08 am by tonykids »
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #5 on: June 24, 2018, 01:49:22 pm »
thanks a lot,I always tend to think to much :-DD  I put it in a dilettante loop...

Code: [Select]
import numpy as np
import struct
addrle = np.uint16(0)
t= '\\20\\x00'
for x in xrange(0,2560,32):
 addrle = '\\x' + '\\x'.join(x.encode('hex') for x in struct.pack('<I', x))
 a = t + addrle
 print a
gives me
Code: [Select]
\20\x00\x00\x00\x00\x00
\20\x00\x20\x00\x00\x00
\20\x00\x40\x00\x00\x00
\20\x00\x60\x00\x00\x00
\20\x00\x80\x00\x00\x00
\20\x00\xa0\x00\x00\x00
\20\x00\xc0\x00\x00\x00
\20\x00\xe0\x00\x00\x00
\20\x00\x00\x01\x00\x00
...
\20\x00\xe0\x09\x00\x00

now lets see if I can put it all together...
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #6 on: June 24, 2018, 02:05:07 pm »
I tried this loop:
Code: [Select]
addrle = np.uint16(0)
t= '\\20\\x00'
for x in xrange(0,2560,32):
 addrle = '\\x' + '\\x'.join(x.encode('hex') for x in struct.pack('<I', x))
 a = t + addrle

 send_msg(0x41, 0x56, 0, 0, a)
 ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)

 print "receive ok at x", x, " =", a

But I get a pipe error:
Code: [Select]
...
File "seek3.py", line 91, in <module>
    send_msg(0x41, 0x56, 0, 0, a)
  File "seek3.py", line 11, in send_msg
    assert (dev.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout) == len(data_or_wLength))
  File "/usr/lib64/python2.7/site-packages/usb/core.py", line 1043, in ctrl_transfer
    self.__get_timeout(timeout))
  File "/usr/lib64/python2.7/site-packages/usb/backend/libusb1.py", line 883, in ctrl_transfer
    timeout))
  File "/usr/lib64/python2.7/site-packages/usb/backend/libusb1.py", line 595, in _check
    raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 32] Pipe error

I suspect I cannot simply add "a" to the end of the send_msg function?  ???

EDIT.. forgot one x in "t= '\\20\\x00'", but still get this error
EDIT2.. okay, sending only one "send_msg(0x41, 0x56, 0, 0, '\x20\x00\x00\x00\x00\x00')" succeeded without error...
« Last Edit: June 24, 2018, 03:38:25 pm by pauledd »
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #7 on: June 24, 2018, 04:47:23 pm »
I dont get it, I first thought the double backslash would make trouble so I formated those parts as "raw" with that r"\x", then before I do send_msg I print the string and it looks fine again in the output but send_msg then failed... do I miss any timing parameter  ??? Because it says "self.__get_timeout(timeout))"...

Code: [Select]
for x in xrange(0,2560,32):
 addrle = r"\x" + r"\x".join(x.encode('hex') for x in struct.pack('<I', x))
 print str(r'\x20\x00') + addrle
 send_msg(0x41, 0x56, 0, 0, str(r'\x20\x00') + addrle)


Code: [Select]
\x20\x00\x00\x00\x00\x00
Traceback (most recent call last):
  File "seek3.py", line 92, in <module>
    send_msg(0x41, 0x56, 0, 0, str(r'\x20\x00') + addrle)
  File "seek3.py", line 12, in send_msg
    assert (dev.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout) == len(data_or_wLength))
  File "/usr/lib64/python2.7/site-packages/usb/core.py", line 1043, in ctrl_transfer
    self.__get_timeout(timeout))
  File "/usr/lib64/python2.7/site-packages/usb/backend/libusb1.py", line 883, in ctrl_transfer
    timeout))
  File "/usr/lib64/python2.7/site-packages/usb/backend/libusb1.py", line 595, in _check
    raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 32] Pipe error
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #8 on: June 24, 2018, 05:51:48 pm »
hmm, seems to be  a timing issue?  :-//
If I send
Code: [Select]
send_msg(0x41, 0x56, 0, 0,' \x20\x00\x00\x00\x00\x00 ')
ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)
send_msg(0x41, 0x56, 0, 0,' \x20\x00\x20\x00\x00\x00 ')
ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)
send_msg(0x41, 0x56, 0, 0,' \x20\x00\x40\x00\x00\x00 ')
ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)
without looping I get no error, BUT just one more send_msg produces the error...
So I can send only 3 of those requests
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #9 on: June 24, 2018, 06:12:18 pm »
next progress... I removed the whitespaces between the data:

Code: [Select]
send_msg(0x41, 0x56, 0, 0,'\x20\x00\x00\x00\x00\x00')
ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)
send_msg(0x41, 0x56, 0, 0,'\x20\x00\x20\x00\x00\x00')
ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)
send_msg(0x41, 0x56, 0, 0,'\x20\x00\x40\x00\x00\x00')
ret7 = receive_msg(0xC1, 0x58, 0, 0, 64)
...
Now I get no more errors, but without loop, I manually filled the 80 sends... seems to be indeed a formatting problem in the loop...
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #10 on: June 25, 2018, 06:59:24 am »
I leave that weired loop and use the 80x send_msg/receive_msg, after that I now continue
with the four remaining commands:

Code: [Select]
# SET_FIRMWARE_INFO_FEATURES = 85 = 0x55
send_msg(0x41, 0x55, 0, 0,'\x15\x00')

# GET_FIRMWARE_INFO = 78 = 0x4E
ret7 = receive_msg(0xC1, 0x4E, 0, 0, 64)

# SET_IMAGE_PROCESSING_MODE = 62 = 0x3E
send_msg(0x41, 0x3E, 0, 0,'\x08\x00')

# SET_OPERATION_MODE = 60 = 0x3C
send_msg(0x41, 0x3C, 0, 0,'\x01\x00')

then the first frame should be taken...

human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #11 on: June 25, 2018, 08:12:00 am »
Just a little bit offtopic, there seems to be a new Seek Thermal App Version 2.1.2, looks like there is new Firmware in it?

human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #12 on: June 25, 2018, 02:35:46 pm »
then the first frame should be taken...

After the last command "SET_OPERATION_MODE" I send this to start image transfer:

Code: [Select]
# START_GET_IMAGE_TRANSFER = 83 = 0x53
send_msg(0x41, 0x53, 0, 0,'\x58\x5B\x01\x00')

so far so good...
now for receiving the first frame I need to send a bulk transfer command, and thats where my knowlege stops...

in the python script for the "Compact" they use this command:
Code: [Select]
ret9  = dev.read(0x81, 0x3F60, 1000)
ret9 += dev.read(0x81, 0x3F60, 1000)
ret9 += dev.read(0x81, 0x3F60, 1000)
ret9 += dev.read(0x81, 0x3F60, 1000)

I am going to think to much again  ;D :
I am not yet sure how to translate that to the "CompactPro", because the second parameter (size?) of cause differs for the Compact Pro, and it looks like they assemble the frame by appending 4 readings ??? ?  0x3F60 is 16224... 4 times is 64896... the raw size of the "Compact" is 208x156=32448 and that's half of 64896... so 4 readings are two raw frames?
Given that the "CompactPro" has 342x260=88920 raw size, half of that would be 44460 (0xADAC). So sending 4x 0xADAC...  :-//


human being - without Windows® - excuse my bad english
 

Offline tonykids

  • Regular Contributor
  • *
  • Posts: 79
Re: Seek Compact Pro python script?
« Reply #13 on: June 26, 2018, 02:42:44 am »
Hey, it's me again ;D
0x3F60 is just because the usb bulktransfer can only transfer a maximum of 16384(0x4000) bytes data every time.
So if your data is more than 16384 bytes,you should read in 16384 bytes(or less)  several times until you get all your data.
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #14 on: June 26, 2018, 06:36:56 am »
hhmmokaay  ;D, thanks. So I will do again some calculations, just to make it clear in my little head:

A full raw frame is 342x260=88920 pixels. Each pixel can have a value of 0-65536, 16bit. That is 88920*16=1422720bit or /8 = 177840 bytes per frame. Given your 16384 bytes max packet size I would assume I have to read 177840/16384=10,8 (11) times to get a full frame ??? Okay I will try that and report back...

human being - without Windows® - excuse my bad english
 

Offline IwuzBornanerd

  • Frequent Contributor
  • **
  • Posts: 318
  • Country: us
Re: Seek Compact Pro python script?
« Reply #15 on: June 26, 2018, 07:25:06 am »
I think the "correct" way, or  maybe the generic way is to do the transfers in a loop wherein you start by asking for the full frame & then after each transfer subtract the number of bytes transferred from the number remaining prior to that transfer and ask for the new remainder each time.  I saw this in someone else's code and implemented it in my own C code.  This works for both the pro & non-pro cameras, but for some reason on the Raspberry Pi the non-pro works better if I ask for a quarter frame each time--otherwise I can get timeout errors  on the first request.  I get timeouts with the pro regardless (on any request), particularly with the timeout set at less than 1sec (1sec seems ridiculous when expecting 8fps or more).  I have not found a "happy" number of bytes to request.

The non-pro ALWAYS sends a frame in 4 chunks regardless of how many bytes I ask for .  The pro does not seem to care how many bytes are requested either.  What I see with my oscilloscope is that with my software the pro sends a frame in 13 or sometimes 14 chunks, but with the Seek apk running [poorly] under Lineage OS on my Raspberry Pi 3B the pro sends a frame in 9 or 10 chunks.
I am not opposed to exercise, unless it is an exercise in futility.
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #16 on: June 26, 2018, 07:44:52 am »
hm, okay. I just watched the Seek App (Android) in my emulator with wireshark, I get 13 chunks everytime...
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #17 on: June 26, 2018, 07:54:33 am »
Okay, that makes sense, it receives 13x13744bytes data, but I gess thats with headers...
The URB length is 13680 and that is *13 = 177840 = full frame.
human being - without Windows® - excuse my bad english
 

Offline tonykids

  • Regular Contributor
  • *
  • Posts: 79
Re: Seek Compact Pro python script?
« Reply #18 on: June 26, 2018, 08:23:28 am »
You are right, that's my fault, I mixed 16384 with 13680 :palm:
And  @IwuzBornanerd's suggestion is  :-+
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #19 on: June 26, 2018, 08:48:24 am »
No problem  ;),

So I looped until my frame list (just leaned that python uses lists  ;D) fills to 177840:
Code: [Select]
frame = []
while (len(frame) <= 163648):
frame += dev.read(0x81, 0x3570, 1000)
print "frame len=", len(frame)

outputs:
Code: [Select]
frame len= 13168
frame len= 26848
frame len= 40528
frame len= 54208
frame len= 67888
frame len= 81568
frame len= 95248
frame len= 108928
frame len= 122608
frame len= 136288
frame len= 149968
frame len= 163648
frame len= 177328

but what next? I printed the first frame just for fun and noticed that all values in it are 0-255. It starts like that:
Quote
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,  0, 0, 0, 0, 0, 0, 0, 0, 212, 55, 133, 5, 0, 0, 0, 0, 0, 0, 0, 1, 164, 1, 102, 3, 88, 17, 190, 00, 0, 0, 0, 0, 0, 108, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0........

Now the next thing would be to start looking for the frame_counter/frame_id... for that "CompactPro" that should be in byte 1 and 2. But in the list I only see zero's  ???
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #20 on: June 26, 2018, 09:46:22 am »
I also noticed that I miss 12 512 bytes from the first bulk return  ???
« Last Edit: June 26, 2018, 09:53:34 am by pauledd »
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #21 on: June 26, 2018, 10:32:00 am »
just digging further  ;D. I observed the usb capture while running the libseek-thermal application. It sometimes also receives 512 bytes less in the first package. Then it repeates the initialisation sequence and in the next run it seems to get the full size... I will try to consider that in my code...
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #22 on: June 26, 2018, 11:56:11 am »
I possibly found the source of the missing 512 bytes. I guess this comes from not releasing the usb device claim that has been done at top of the script. So I added the following at the end of my script where I beleave the dispose command is the important one:
Code: [Select]
send_msg(0x41, 0x3C, 0, 0,'\x00\x00')
send_msg(0x41, 0x3C, 0, 0,'\x00\x00')
send_msg(0x41, 0x3C, 0, 0,'\x00\x00')
usb.util.dispose_resources(dev)
With that almost all bulk transfers start with the full size, now I can continue to find the frame id/counter position
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #23 on: June 26, 2018, 01:28:39 pm »
some progress. I just tried a loop to read a full frame and then print the values at frame[2] and frame[4].
Code: [Select]
while True:
frame = []
send_msg(0x41, 0x53, 0, 0,'\x58\x5B\x01\x00')
frame = dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
frame += dev.read(0x81, 0x3570, 0x3E8)
print frame[2], frame[4]

Thats the first time I hear the shutter clicking  ;D and I get output with an increasing number that is hopefully indeed the frame counter
and another number that first goes stupid but then settles at value 3 and everytime the shutter clicks it changes ..3/6/5/1/3...
Code: [Select]
1 4
3 9
5 14
7 8
9 7
11 5
26 6
28 5
30 1
33 3
35 3
37 3
39 3
41 3
43 3
45 3
47 3
49 3
51 3
53 3
55 3
57 3
59 3
61 3
63 3
65 3
67 3
69 3
72 6
74 5
76 1
79 3
81 3
83 3
85 3
human being - without Windows® - excuse my bad english
 

Offline IwuzBornanerd

  • Frequent Contributor
  • **
  • Posts: 318
  • Country: us
Re: Seek Compact Pro python script?
« Reply #24 on: June 26, 2018, 08:39:26 pm »
hm, okay. I just watched the Seek App (Android) in my emulator with wireshark, I get 13 chunks everytime...

But your camera is a non-fast frame unit, correct?  OR does the Seek app identify it as Seek Compact PRO FF (like it does with my camera)?

The first 5 frames, status numbers 4, 9, 14, 8 & 7 seem to be related to calibration.  I (and maybe only I) believe that the status 9 frame is the thermistor curve for the sensor; basically a lookup table for determining the temperature of a pixel and that is how I use it in my code.
I am not opposed to exercise, unless it is an exercise in futility.
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #25 on: June 27, 2018, 06:58:43 am »
But your camera is a non-fast frame unit, correct?  OR does the Seek app identify it as Seek Compact PRO FF (like it does with my camera)?
Yes, its the normal CompactPro (ID 289d:0011)

I currently trying to figure out whether my frames are valid ones or whether where to look for the actual image in it. I only concentrate on the nomal frames with id=3.

I got a function from stackoverflow that converts all pairs of uint8 values to into a single uint16 value (I guess this is what happens in the correct_endianness function in the libseek-thermal lib). Of cause the size off the array is then half 177840 = 88920...

Code: [Select]
while (status != 3):
frame = []
send_msg(0x41, 0x53, 0, 0,'\x58\x5B\x01\x00')
frame = dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
status = frame[4]
if (status == 3):
frame16 = array.array('H', ((j << 8 ) | i
  for (i,j)
  in zip(frame[::2], frame[1::2])))
print "frame_uint8=", frame[:32]
print "frame_uint16=", frame16[:32]
Here I've printed two lines with 32 positions for the same id=3 frame, the first is the unprocessed uint8 frame, the second is the uint16 array with the data from the uint8 array. Now in the uint16 data I can see that the frame_count byte is at index frame16[1]=33, and the frame_id byte is at frame16[2] = 3, as expected... the index for those two changed to the half number (the frame_id in the uint16 was at frame[4]):
Code: [Select]
frame_uint8= array('B', [121, 5, 33, 0, 3, 0, 0, 0, 33, 0, 31, 25, 152, 58, 0, 0, 0, 0, 0, 0, 48, 0, 37, 55, 0, 0, 0, 0, 0, 0, 0, 0])
frame_uint16= array('H', [1401, 33, 3, 0, 33, 6431, 15000, 0, 0, 0, 48, 14117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

I am not shure if I can simply throw the frame16 data into an cv2::Mat/PIL::whatever to display the image or whether I need to crop the raw dimensions to the 320x240, and if so, I am not sure how to do it. The writer of this python code just put the array into "calimg = Image.fromstring("I", (208,156), ret9, "raw", "I;16")" without cropping it to 207x154 for the "Compact"...

I know the C++ code in the libseek-thermal lib contains all the steps but I am quite awkward in understanding it  :o . Thats why I take it to pieces here in python ;D
« Last Edit: June 27, 2018, 07:03:20 am by pauledd »
human being - without Windows® - excuse my bad english
 

Offline IwuzBornanerd

  • Frequent Contributor
  • **
  • Posts: 318
  • Country: us
Re: Seek Compact Pro python script?
« Reply #26 on: June 27, 2018, 07:39:21 am »
Once you have converted to 16 bit numbers you then need to subtract the values in the shutter frame (ID=1) from the frame 3 values.  This gets you values that correspond to the difference in temperature between the shutter & the scene.  The values can be both negative & positive.  That is the first level of correction.  You then need to apply gain correction factors to each pixel.  You can use the values in the frame with ID=4 by dividing each number by the average of all values and using the results as percentage multipliers for each pixel in the frame 3 minus frame 1 set of values.  OR you can make your own correction factors (which are better) by capturing a frame 3 with the camera warmed up & pointed at a uniform ambient temperature surface, subtracting the preceding frame 1 from that and dividing each value by the average.   I think I have that right without reviewing my code.  You will have to figure out a good way to deal with the +/- values & assigning colors or gray shades.  Adding a simple offset is one way.  Figuring temperature is another complexity...

Is that clear as mud?  ;) 
I am not opposed to exercise, unless it is an exercise in futility.
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #27 on: June 28, 2018, 06:47:48 am »
*to the note, just in case I cant remember again later...

I am currently still totally stuck at raw conversion  :clap:
I went some steps backward and simply outputted the raw frames in binary format like that:

Code: [Select]
while status != 3:
frame = np.uint16()
send_msg(0x41, 0x53, 0, 0,'\x58\x5B\x01\x00')
frame = dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
status = frame[4]
print status

thefile = open("frames/frame_id_"+str(status)+".raw", 'w')
thefile.write(struct.pack('177840B', *frame))

I now have:
Code: [Select]
frame_id_14.raw
frame_id_1.raw
frame_id_3.raw
frame_id_4.raw
frame_id_5.raw
frame_id_6.raw
frame_id_7.raw
frame_id_8.raw
frame_id_9.raw

I then used imagemagik to convert them:

Code: [Select]
for i in $(ls frames/);do convert -depth 16 -endian lsb -size 342x260 gray:$i -auto-level $i.png;done
conversion failed for id: 4,8,9,14 "convert: no images defined"

for the rest I got these images:
id1

id3

id5

id6

id7


In id3 I can see the faint thermal object my cam is pionting at... I get closer  :)


Just another sidenote:
ALL the camera initialisation steps from:
Code: [Select]
# SET_OPERATION_MODE = 60; 0x41=send,0x3C=60
send_msg(0x41, 0x3C, 0, 0, '\x00\x00')
...
down to:
Code: [Select]
...
# GET_FIRMWARE_INFO = 78 = 0x4E
ret7 = receive_msg(0xC1, 0x4E, 0, 0, 64)
can be deleted. I found out after accidental delete that the cam starts image transfer with just this commands:
Code: [Select]
#SET_IMAGE_PROCESSING_MODE = 62 = 0x3E
send_msg(0x41, 0x3E, 0, 0,'\x08\x00')

# SET_OPERATION_MODE = 60 = 0x3C
send_msg(0x41, 0x3C, 0, 0,'\x01\x00')
after that you can start the bulk transfer... This seems to work at least for my CompactPro device...

I now continue to fiddle with that  :palm: array stuff that my script outputs raw png's...
« Last Edit: June 28, 2018, 06:49:37 am by pauledd »
human being - without Windows® - excuse my bad english
 
The following users thanked this post: DaneLaw

Offline IwuzBornanerd

  • Frequent Contributor
  • **
  • Posts: 318
  • Country: us
Re: Seek Compact Pro python script?
« Reply #28 on: June 28, 2018, 08:34:09 am »
I also found that much of the setup stuff can be eliminated, but I can't verify if it is the same stuff you deleted.  I suppose most of it is "defaults"
I am not opposed to exercise, unless it is an exercise in futility.
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #29 on: June 28, 2018, 05:05:02 pm »
I made a good step foreward :). After hours fiddling with lists/numpy-arrays/opencv/endianness  :rant:
I managed to get Images from opencv. The problem was simple... I simply did not realize that the data in my lists/numpy-arrays was 1d... for displaying/manipulating images in numpy arrays with opencv I needed the data to be 2d. So one simple numpy function called reshape did the job.
And I found a simpler way to convert the raw frame from uint8 LSB to uint16 MSB:

Code: [Select]
...
frame = dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
frame += dev.read(0x81, 0x3570, tout)
...
npframe = np.asarray(frame, dtype='<B')
npframe.dtype = np.uint16
img = npframe.reshape(260,342)
cv2.normalize(img,img, 0,65535,cv2.NORM_MINMAX)
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
cv2.resizeWindow('image', 600,600)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Now I can define an ROI and cut out the actual image from the raw frame and start all the post processing stuff that I want. One thing I found interesting was that the actual image has dimensions wider than those from the
specs  ??? I just googled for 324x254 and found that others here had already discovered that. So
for the CompactPro I get 4-top, 18-right and2-bottom lines that are outside of the image.
human being - without Windows® - excuse my bad english
 

Offline pauleddTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: de
  • Riesige Gepanzerte Luftschiffe
Re: Seek Compact Pro python script?
« Reply #30 on: July 05, 2018, 04:39:51 pm »
I just wonder where this "patent pixels" are in my id3 image above? Are that the total black pixels that cover 2 pixels each? Would be strange if that would be dead pixels, but I would expect the patent to be in a pattern well ordered over the whole image as I saw from the other users here  :o
human being - without Windows® - excuse my bad english
 

Offline IwuzBornanerd

  • Frequent Contributor
  • **
  • Posts: 318
  • Country: us
Re: Seek Compact Pro python script?
« Reply #31 on: July 05, 2018, 07:06:11 pm »
My Pro does not have "patent pixels"; at least not a noticeable number of regular (or even irregular) zero pixels.
I am not opposed to exercise, unless it is an exercise in futility.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf