Products > Thermal Imaging

ThermalExpert reverse engineering jar & dll

(1/7) > >>

frenky:
In the attachment are two versions of the same decompiled jar file which can be used as library for android app.
In them you can see USB communication and sensor data manipulation.
If code in one file looks strange, just look into other file where it might look more straightforward...

Interesting bits of code:

Get data from sensor

--- Code: ---private int Read(byte[] buf, int iSize) {
            int iOffset = 0;
            if (iSize % 512 != 0) {
                iSize += 512 - iSize % 512;
            }
            int iRepeat = iSize / 16384;
            if (iSize % 16384 != 0) {
                ++iRepeat;
            }
            int iValue = iSize >> 9;
            try {
                if (this.m_USBConnection.controlTransfer(128, 134, iValue, 48879, this.m_VenBuf, 8, this.m_iReadTimeOut) < 0) {
                    return -1;
                }
            }
            catch (Exception e) {
                e.printStackTrace();
                this.m_Handler.obtainMessage(4, 0, 0, (Object)e.getLocalizedMessage()).sendToTarget();
                return -1;
            }
            int iRecvSize = 0;
            int iRecv = 0;
            ByteBuffer bf = ByteBuffer.wrap(buf);
            byte[] bufTemp = new byte[16384];
            try {
                int i = 0;
                do {
                    if (i >= iRepeat) {
                        return iOffset;
                    }
                    iRecvSize = Math.min(16384, iSize);
                    iRecv = this.m_USBConnection.bulkTransfer(this.m_USBRecvEndPoint, bufTemp, iRecvSize, this.m_iReadTimeOut);
                    if (iRecv != iRecvSize) {
                        return -1;
                    }
                    bf.put(bufTemp, 0, iRecvSize);
                    iOffset += iRecv;
                    iSize -= 16384;
                    ++i;
                } while (true);
            }
            catch (Exception e) {
                e.printStackTrace();
                this.m_Handler.obtainMessage(4, 0, 0, (Object)e.getLocalizedMessage()).sendToTarget();
                return iOffset;
            }
        }

--- End code ---

Is actual sensor height 296? Data from sensor is 227,328 bytes which matches: 2byte * 384 * 296:

--- Code: ---private final int m_fiQVGAPlusSensorWidth = 384;
        private final int m_fiQVGAPlusSensorHeight = 296;
        private final int m_fiQVGAPlusActiveHeight = 288;

--- End code ---


frenky:
Dead pixel correction seems quite similar to JadeW's code...

--- Code: ---private void DeadCorrectionBeforeAGC() {
        int x;
        int cnt = 0;
        int sum = 0;
        int lower = - this.commData.getWindowingWidth();
        int upper = - lower;
        int right = 1;
        int left = -1;
        int y = 0;
        int pos = 0;
        while (y < this.commData.getWindowingHeight()) {
            x = 0;
            while (x < this.commData.getWindowingWidth()) {
                if (this.commData.m_pbyDeadData[pos] != 0) {
                    cnt = 0;
                    sum = 0;
                    if (y < this.commData.getWindowingHeight() - 1 && this.commData.m_pbyDeadData[pos + this.commData.getWindowingWidth()] == 0) {
                        sum += this.prevAGCData[pos + upper];
                        ++cnt;
                    }
                    if (y > 0 && this.commData.m_pbyDeadData[pos - this.commData.getWindowingWidth()] == 0) {
                        sum += this.prevAGCData[pos + lower];
                        ++cnt;
                    }
                    if (x > 0 && this.commData.m_pbyDeadData[pos - 1] == 0) {
                        sum += this.prevAGCData[pos + left];
                        ++cnt;
                    }
                    if (x < this.commData.getWindowingWidth() - 1 && this.commData.m_pbyDeadData[pos + 1] == 0) {
                        sum += this.prevAGCData[pos + right];
                        ++cnt;
                    }
                    this.prevAGCAfterDeadData[pos] = cnt > 0 ? (int)((double)(sum / cnt) + 0.5) : 0;
                } else {
                    this.prevAGCAfterDeadData[pos] = this.prevAGCData[pos];
                }
                ++x;
                ++pos;
            }
            ++y;
        }
        y = 0;
        pos = 0;
        while (y < this.commData.getWindowingHeight()) {
            x = 0;
            while (x < this.commData.getWindowingWidth()) {
                cnt = 0;
                sum = 0;
                if (this.commData.m_pb2DeadData[pos]) {
                    if (y < this.commData.getWindowingHeight() - 1 && !this.commData.m_pb2DeadData[pos + upper]) {
                        sum += this.prevAGCData[pos + upper];
                        ++cnt;
                    }
                    if (y > 0 && !this.commData.m_pb2DeadData[pos + lower]) {
                        sum += this.prevAGCData[pos + lower];
                        ++cnt;
                    }
                    if (x > 0 && !this.commData.m_pb2DeadData[pos + left]) {
                        sum += this.prevAGCData[pos + left];
                        ++cnt;
                    }
                    if (x < this.commData.getWindowingWidth() - 1 && !this.commData.m_pb2DeadData[pos + right]) {
                        sum += this.prevAGCData[pos + right];
                        ++cnt;
                    }
                    this.prevAGCAfterDeadData[pos] = cnt > 0 ? (int)((double)(sum / cnt) + 0.5) : 0;
                }
                ++x;
                ++pos;
            }
            ++y;
        }
        y = 0;
        pos = 0;
        while (y < this.commData.getWindowingHeight()) {
            x = 0;
            while (x < this.commData.getWindowingWidth()) {
                cnt = 0;
                sum = 0;
                if (this.commData.m_pb3DeadData[pos]) {
                    if (y < this.commData.getWindowingHeight() - 1 && !this.commData.m_pb3DeadData[pos + this.commData.getWindowingWidth()]) {
                        sum += this.prevAGCData[pos + upper];
                        ++cnt;
                    }
                    if (y > 0 && !this.commData.m_pb3DeadData[pos - this.commData.getWindowingWidth()]) {
                        sum += this.prevAGCData[pos + lower];
                        ++cnt;
                    }
                    if (x > 0 && !this.commData.m_pb3DeadData[pos - 1]) {
                        sum += this.prevAGCData[pos + left];
                        ++cnt;
                    }
                    if (x < this.commData.getWindowingWidth() - 1 && !this.commData.m_pb3DeadData[pos + 1]) {
                        sum += this.prevAGCData[pos + right];
                        ++cnt;
                    }
                    this.prevAGCAfterDeadData[pos] = cnt > 0 ? (int)((double)(sum / cnt) + 0.5) : 0;
                }
                ++x;
                ++pos;
            }
            ++y;
        }
        y = 0;
        pos = 0;
        while (y < this.commData.getWindowingHeight()) {
            x = 0;
            while (x < this.commData.getWindowingWidth()) {
                cnt = 0;
                sum = 0;
                if (this.commData.m_pb4DeadData[pos]) {
                    if (y < this.commData.getWindowingHeight() - 1 && !this.commData.m_pb4DeadData[pos + this.commData.getWindowingWidth()]) {
                        sum += this.prevAGCData[pos + upper];
                        ++cnt;
                    }
                    if (y > 0 && !this.commData.m_pb4DeadData[pos - this.commData.getWindowingWidth()]) {
                        sum += this.prevAGCData[pos + lower];
                        ++cnt;
                    }
                    if (x > 0 && !this.commData.m_pb4DeadData[pos - 1]) {
                        sum += this.prevAGCData[pos + left];
                        ++cnt;
                    }
                    if (x < this.commData.getWindowingWidth() - 1 && !this.commData.m_pb4DeadData[pos + 1]) {
                        sum += this.prevAGCData[pos + right];
                        ++cnt;
                    }
                    this.prevAGCAfterDeadData[pos] = cnt > 0 ? (int)((double)(sum / cnt) + 0.5) : 0;
                }
                ++x;
                ++pos;
            }
            ++y;
        }
    }

--- End code ---

JadeW code:

--- Code: ---void ThermalFrame::fixPixels(const std::vector<uint16_t> & pixels, bool use_given_pixel)
{
for (size_t i = 0; i < pixels.size(); ++i)
{
uint32_t pixel = pixels[i];

size_t x = pixel % 206;
size_t y = pixel / 206;


uint32_t val = use_given_pixel ? m_pixels[pixel] * 2 : 0;
uint8_t nr = use_given_pixel ? 2 : 0;

if (y > 0 && !m_bad_pixels[x][y - 1])
{
val += m_pixels[(y - 1) * 206 + x];
++nr;
}

if (y < 156 - 1 && !m_bad_pixels[x][y + 1])
{
val += m_pixels[(y + 1) * 206 + x];
++nr;
}

if (x > 0 && !m_bad_pixels[x - 1][y])
{
val += m_pixels[y * 206 + (x - 1)];
++nr;
}

if (x < 206 - 1 && !m_bad_pixels[x + 1][y])
{
val += m_pixels[y * 206 + x + 1];
++nr;
}

if (nr)
{
val /= nr;
m_pixels[pixel] = val;
}
else
m_pixels[pixel] = m_avg_val;
}
}

--- End code ---

frenky:
Sequence of first frames by joe-c:

https://www.eevblog.com/forum/thermal-imaging/i3-thermalexpert-custom-software/msg1055775/#msg1055775

frenky:
T.E. Usb identifiers:
VID: 0x0547
PID: 0x0080

VID belongs to "Anchor Chips, Inc.".

frenky:
Another interesting observation.

DLL call that captures single frame from sensor takes only 10ms (RecvImage or RecvImageDouble).
So sensor is capable of 100fps.
But If you make fast sequential calls you will notice approx 100ms delay between responses so that you can't go over 9fps...

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod