mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Compare commits
43 Commits
a9e3feec16
...
b591b39ab9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b591b39ab9 | ||
|
|
8e1682f58d | ||
|
|
7cbdb927da | ||
|
|
5ae4a02d41 | ||
|
|
3e22e0ea03 | ||
|
|
30f499ea2d | ||
|
|
15070dd722 | ||
|
|
77c8cc5fe0 | ||
|
|
8890c80e3d | ||
|
|
c8fc7903f4 | ||
|
|
8403340257 | ||
|
|
55488e08a5 | ||
|
|
8ece14c1a7 | ||
|
|
5f766069ad | ||
|
|
21ceec4229 | ||
|
|
29e94ad8e8 | ||
|
|
4b1837f72e | ||
|
|
200c702d1d | ||
|
|
9d0e012b1c | ||
|
|
46961ffe0b | ||
|
|
643676c2bb | ||
|
|
7c3f3d58c8 | ||
|
|
bb8ed01a23 | ||
|
|
f8d84c2fe1 | ||
|
|
82b2471b11 | ||
|
|
6a446b139b | ||
|
|
ccf6f14e7e | ||
|
|
a62c5ea3ce | ||
|
|
cc9b9ff29b | ||
|
|
c7e0056a45 | ||
|
|
34687cda83 | ||
|
|
8eca7f598a | ||
|
|
a38bc7df52 | ||
|
|
cd10451d49 | ||
|
|
e49e49eb36 | ||
|
|
e56fa55dec | ||
|
|
78ad9448dc | ||
|
|
fa65d7af94 | ||
|
|
5e9bc80a2e | ||
|
|
f54fa0c0a2 | ||
|
|
cdb0d91d74 | ||
|
|
29ad945adb | ||
|
|
715c4cbba6 |
33
.github/workflows/firmware.yml
vendored
33
.github/workflows/firmware.yml
vendored
@ -48,11 +48,26 @@ jobs:
|
||||
- ARDUINO_NICLA_VISION
|
||||
- ARDUINO_NANO_RP2040_CONNECT
|
||||
- ARDUINO_NANO_33_BLE_SENSE
|
||||
- DOCKER
|
||||
profile: [0] # default profile
|
||||
qemu: [false]
|
||||
profile: [0]
|
||||
artifacts: [true]
|
||||
include:
|
||||
- target: DOCKER
|
||||
qemu: false
|
||||
profile: 0
|
||||
artifacts: false
|
||||
- target: OPENMV_N6
|
||||
qemu: false
|
||||
profile: 1
|
||||
artifacts: false
|
||||
- target: MPS2_AN500
|
||||
qemu: true
|
||||
profile: 0
|
||||
artifacts: false
|
||||
- target: MPS3_AN547
|
||||
qemu: true
|
||||
profile: 0
|
||||
artifacts: false
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: '⏳ Checkout repository'
|
||||
@ -82,6 +97,8 @@ jobs:
|
||||
|
||||
- name: '🛠 Install dependencies'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y qemu-system-arm
|
||||
pip install -r .github/workflows/requirements.txt
|
||||
flake8 --version
|
||||
pytest --version
|
||||
@ -104,10 +121,14 @@ jobs:
|
||||
run: source tools/ci.sh && ci_install_stedgeai ${HOME}/cache/stedgeai
|
||||
|
||||
- name: '🏗 Build firmware'
|
||||
run: source tools/ci.sh && ci_build_target ${{ matrix.target }} ${{ matrix.profile }}
|
||||
run: source tools/ci.sh && ci_build_target ${{ matrix.target }} ${{ matrix.qemu }} ${{ matrix.profile }} ${{ matrix.artifacts }}
|
||||
|
||||
- name: '🧪 Run QEMU tests'
|
||||
if: matrix.qemu
|
||||
run: source tools/ci.sh && ci_run_qemu_tests ${{ matrix.target }}
|
||||
|
||||
- name: '⬆ Upload artifacts'
|
||||
if: matrix.target != 'DOCKER' && matrix.profile == 0
|
||||
if: matrix.artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
@ -202,7 +223,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: '🔥 Create stable release'
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
with:
|
||||
draft: true
|
||||
files: firmware_*.zip
|
||||
@ -254,7 +275,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: '🔥 Create development release'
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
with:
|
||||
draft: false
|
||||
name: Development Release
|
||||
|
||||
1
.github/workflows/requirements.txt
vendored
1
.github/workflows/requirements.txt
vendored
@ -5,3 +5,4 @@ tabulate==0.9.0
|
||||
cryptography==44.0.1
|
||||
pyelftools==0.27
|
||||
colorama==0.4.6
|
||||
mpremote
|
||||
|
||||
@ -38,6 +38,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
|
||||
@ -32,6 +32,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
|
||||
@ -38,6 +38,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
|
||||
164
boards/MPS2_AN500/imlib_config.h
Normal file
164
boards/MPS2_AN500/imlib_config.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2025 OpenMV, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Image library configuration.
|
||||
*/
|
||||
#ifndef __IMLIB_CONFIG_H__
|
||||
#define __IMLIB_CONFIG_H__
|
||||
|
||||
// Enable Image I/O
|
||||
#define IMLIB_ENABLE_IMAGE_IO
|
||||
|
||||
// Enable Image File I/O
|
||||
#define IMLIB_ENABLE_IMAGE_FILE_IO
|
||||
|
||||
// Enable LAB LUT
|
||||
#define IMLIB_ENABLE_LAB_LUT
|
||||
|
||||
// Enable YUV LUT
|
||||
//#define IMLIB_ENABLE_YUV_LUT
|
||||
|
||||
// Enable ISP ops
|
||||
#define IMLIB_ENABLE_ISP_OPS
|
||||
|
||||
// Enable binary ops
|
||||
#define IMLIB_ENABLE_BINARY_OPS
|
||||
|
||||
// Enable math ops
|
||||
#define IMLIB_ENABLE_MATH_OPS
|
||||
|
||||
// Enable flood_fill()
|
||||
#define IMLIB_ENABLE_FLOOD_FILL
|
||||
|
||||
// Enable mean()
|
||||
#define IMLIB_ENABLE_MEAN
|
||||
|
||||
// Enable median()
|
||||
#define IMLIB_ENABLE_MEDIAN
|
||||
|
||||
// Enable mode()
|
||||
#define IMLIB_ENABLE_MODE
|
||||
|
||||
// Enable midpoint()
|
||||
#define IMLIB_ENABLE_MIDPOINT
|
||||
|
||||
// Enable morph()
|
||||
#define IMLIB_ENABLE_MORPH
|
||||
|
||||
// Enable Gaussian
|
||||
#define IMLIB_ENABLE_GAUSSIAN
|
||||
|
||||
// Enable Laplacian
|
||||
#define IMLIB_ENABLE_LAPLACIAN
|
||||
|
||||
// Enable bilateral()
|
||||
#define IMLIB_ENABLE_BILATERAL
|
||||
|
||||
// Enable linpolar()
|
||||
#define IMLIB_ENABLE_LINPOLAR
|
||||
|
||||
// Enable logpolar()
|
||||
#define IMLIB_ENABLE_LOGPOLAR
|
||||
|
||||
// Enable lens_corr()
|
||||
#define IMLIB_ENABLE_LENS_CORR
|
||||
|
||||
// Enable rotation_corr()
|
||||
#define IMLIB_ENABLE_ROTATION_CORR
|
||||
|
||||
// Enable phasecorrelate()
|
||||
#if defined(IMLIB_ENABLE_ROTATION_CORR)
|
||||
#define IMLIB_ENABLE_FIND_DISPLACEMENT
|
||||
#endif
|
||||
|
||||
// Enable get_similarity()
|
||||
#define IMLIB_ENABLE_GET_SIMILARITY
|
||||
|
||||
// Enable find_lines()
|
||||
#define IMLIB_ENABLE_FIND_LINES
|
||||
|
||||
// Enable find_line_segments()
|
||||
#define IMLIB_ENABLE_FIND_LINE_SEGMENTS
|
||||
|
||||
// Enable find_circles()
|
||||
#define IMLIB_ENABLE_FIND_CIRCLES
|
||||
|
||||
// Enable find_rects()
|
||||
#define IMLIB_ENABLE_FIND_RECTS
|
||||
|
||||
// Enable find_qrcodes() (14 KB)
|
||||
#define IMLIB_ENABLE_QRCODES
|
||||
|
||||
// Enable find_apriltags() (64 KB)
|
||||
#define IMLIB_ENABLE_APRILTAGS
|
||||
#define IMLIB_ENABLE_APRILTAGS_TAG36H11
|
||||
|
||||
// Enable fine find_apriltags() - (8-way connectivity versus 4-way connectivity)
|
||||
// #define IMLIB_ENABLE_FINE_APRILTAGS
|
||||
|
||||
// Enable high res find_apriltags() - uses more RAM
|
||||
// #define IMLIB_ENABLE_HIGH_RES_APRILTAGS
|
||||
|
||||
// Enable find_datamatrices() (26 KB)
|
||||
#define IMLIB_ENABLE_DATAMATRICES
|
||||
|
||||
// Enable find_barcodes() (42 KB)
|
||||
#define IMLIB_ENABLE_BARCODES
|
||||
|
||||
// Enable find_features() and Haar cascades.
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
|
||||
// Enable Tensor Flow
|
||||
#define IMLIB_ENABLE_STAI
|
||||
|
||||
// Enable AGAST.
|
||||
#define IMLIB_ENABLE_AGAST
|
||||
|
||||
// Enable find_template()
|
||||
#define IMLIB_FIND_TEMPLATE
|
||||
|
||||
// Enable find_lbp()
|
||||
#define IMLIB_ENABLE_FIND_LBP
|
||||
|
||||
// Enable find_keypoints()
|
||||
#if defined(IMLIB_ENABLE_FAST) || defined(IMLIB_ENABLE_AGAST)
|
||||
#define IMLIB_ENABLE_FIND_KEYPOINTS
|
||||
#endif
|
||||
|
||||
// Enable load, save and match descriptor
|
||||
#define IMLIB_ENABLE_DESCRIPTOR
|
||||
|
||||
// Enable find_hog()
|
||||
#define IMLIB_ENABLE_HOG
|
||||
|
||||
// Enable selective_search()
|
||||
#define IMLIB_ENABLE_SELECTIVE_SEARCH
|
||||
|
||||
// Enable PNG encoder/decoder
|
||||
#define IMLIB_ENABLE_PNG_ENCODER
|
||||
#define IMLIB_ENABLE_PNG_DECODER
|
||||
|
||||
// Stereo Imaging
|
||||
#define IMLIB_ENABLE_STEREO_DISPARITY
|
||||
|
||||
#endif //__IMLIB_CONFIG_H__
|
||||
5
boards/MPS2_AN500/manifest.py
Normal file
5
boards/MPS2_AN500/manifest.py
Normal file
@ -0,0 +1,5 @@
|
||||
# OpenMV library
|
||||
add_library("openmv-lib", "$(OMV_LIB_DIR)")
|
||||
|
||||
# Libraries
|
||||
require("ml", library="openmv-lib")
|
||||
71
boards/MPS2_AN500/omv_boardconfig.h
Normal file
71
boards/MPS2_AN500/omv_boardconfig.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2025 OpenMV, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Board configuration and pin definitions.
|
||||
*/
|
||||
#ifndef __OMV_BOARDCONFIG_H__
|
||||
#define __OMV_BOARDCONFIG_H__
|
||||
|
||||
// Architecture info
|
||||
#define OMV_BOARD_ARCH "MPS2 AN500" // 33 chars max
|
||||
#define OMV_BOARD_TYPE "M7"
|
||||
|
||||
// JPEG configuration.
|
||||
#define OMV_JPEG_CODEC_ENABLE (0)
|
||||
#define OMV_JPEG_QUALITY_LOW (35)
|
||||
#define OMV_JPEG_QUALITY_HIGH (60)
|
||||
#define OMV_JPEG_QUALITY_THRESHOLD (160 * 120 * 2)
|
||||
|
||||
// UMM heap block size
|
||||
#define OMV_UMM_BLOCK_SIZE 16
|
||||
|
||||
#define OMV_MAIN_MEMORY SRAM1 // Data/BSS memory
|
||||
#define OMV_STACK_MEMORY SRAM1 // stack memory
|
||||
#define OMV_STACK_SIZE (64K)
|
||||
#define OMV_FB_MEMORY SRAM1 // Framebuffer, fb_alloc
|
||||
#define OMV_FB_SIZE (1M) // FB memory: header + QVGA/GS image
|
||||
#define OMV_FB_ALLOC_SIZE (1850K) // minimum fb alloc size
|
||||
#define OMV_GC_BLOCK0_MEMORY SRAM1 // Main GC block
|
||||
#define OMV_GC_BLOCK0_SIZE (1M)
|
||||
#define OMV_SB_SIZE (128K) // IDE JPEG buffer size (header + data).
|
||||
|
||||
// Memory map.
|
||||
#define OMV_SRAM1_ORIGIN 0x20000000
|
||||
#define OMV_SRAM1_LENGTH 4M
|
||||
|
||||
#define OMV_FLASH_ISR_ORIGIN 0x00000000
|
||||
#define OMV_FLASH_ISR_LENGTH 4K
|
||||
|
||||
#define OMV_FLASH_TXT_ORIGIN 0x00001000
|
||||
#define OMV_FLASH_TXT_LENGTH 4092M
|
||||
|
||||
// CSI configuration.
|
||||
#define OMV_CSI_I2C_ID (0)
|
||||
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_STANDARD)
|
||||
#define OMV_CSI_CLK_SOURCE (OMV_CSI_CLK_SOURCE_TIM)
|
||||
#define OMV_CSI_CLK_FREQUENCY (24000000)
|
||||
#define OMV_CSI_HW_CROP_ENABLE (0)
|
||||
#define OMV_CSI_MAX_DEVICES (3)
|
||||
|
||||
#define OMV_SOFTCSI_ENABLE (1)
|
||||
#endif //__OMV_BOARDCONFIG_H__
|
||||
24
boards/MPS2_AN500/omv_boardconfig.mk
Executable file
24
boards/MPS2_AN500/omv_boardconfig.mk
Executable file
@ -0,0 +1,24 @@
|
||||
CPU=cortex-m7
|
||||
FPU=fpv5-d16
|
||||
PORT=qemu
|
||||
QEMU_MACHINE=mps2-an500
|
||||
OMV_ENABLE_BL=0
|
||||
OMV_LEPTON_SDK_ENABLE=0
|
||||
OMV_BOARD_CFLAGS= -DQEMU_SOC_MPS2 \
|
||||
-DCPU_FREQ_HZ=25000000
|
||||
MICROPY_PY_CSI = 1
|
||||
MICROPY_PY_CSI_NG = 1
|
||||
MICROPY_PY_FIR = 0
|
||||
MICROPY_PY_ULAB = 1
|
||||
MICROPY_PY_WINC1500 = 0
|
||||
MICROPY_PY_DISPLAY = 0
|
||||
MICROPY_PY_TV = 0
|
||||
MICROPY_PY_ML = 1
|
||||
MICROPY_PY_ML_TFLM = 1
|
||||
MICROPY_PY_LWIP = 0
|
||||
MICROPY_PY_SSL = 0
|
||||
MICROPY_PY_SSL_ECDSA_SIGN_ALT = 0
|
||||
MICROPY_SSL_MBEDTLS = 0
|
||||
MICROPY_PY_NETWORK_CYW43 = 0
|
||||
MICROPY_PY_BLUETOOTH = 0
|
||||
MICROPY_BLUETOOTH_NIMBLE = 0
|
||||
6
boards/MPS2_AN500/romfs.json
Normal file
6
boards/MPS2_AN500/romfs.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"0": {
|
||||
"size": "0x20000",
|
||||
"entries": [ ]
|
||||
}
|
||||
}
|
||||
17
boards/MPS2_AN500/ulab_config.h
Normal file
17
boards/MPS2_AN500/ulab_config.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013-2016 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* Ulab config file.
|
||||
*
|
||||
*/
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (0)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
#define ULAB_FFT_IS_NUMPY_COMPATIBLE (0)
|
||||
#endif //__ULAB_CONFIG_H__
|
||||
164
boards/MPS3_AN547/imlib_config.h
Normal file
164
boards/MPS3_AN547/imlib_config.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2025 OpenMV, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Image library configuration.
|
||||
*/
|
||||
#ifndef __IMLIB_CONFIG_H__
|
||||
#define __IMLIB_CONFIG_H__
|
||||
|
||||
// Enable Image I/O
|
||||
#define IMLIB_ENABLE_IMAGE_IO
|
||||
|
||||
// Enable Image File I/O
|
||||
#define IMLIB_ENABLE_IMAGE_FILE_IO
|
||||
|
||||
// Enable LAB LUT
|
||||
#define IMLIB_ENABLE_LAB_LUT
|
||||
|
||||
// Enable YUV LUT
|
||||
//#define IMLIB_ENABLE_YUV_LUT
|
||||
|
||||
// Enable ISP ops
|
||||
#define IMLIB_ENABLE_ISP_OPS
|
||||
|
||||
// Enable binary ops
|
||||
#define IMLIB_ENABLE_BINARY_OPS
|
||||
|
||||
// Enable math ops
|
||||
#define IMLIB_ENABLE_MATH_OPS
|
||||
|
||||
// Enable flood_fill()
|
||||
#define IMLIB_ENABLE_FLOOD_FILL
|
||||
|
||||
// Enable mean()
|
||||
#define IMLIB_ENABLE_MEAN
|
||||
|
||||
// Enable median()
|
||||
#define IMLIB_ENABLE_MEDIAN
|
||||
|
||||
// Enable mode()
|
||||
#define IMLIB_ENABLE_MODE
|
||||
|
||||
// Enable midpoint()
|
||||
#define IMLIB_ENABLE_MIDPOINT
|
||||
|
||||
// Enable morph()
|
||||
#define IMLIB_ENABLE_MORPH
|
||||
|
||||
// Enable Gaussian
|
||||
#define IMLIB_ENABLE_GAUSSIAN
|
||||
|
||||
// Enable Laplacian
|
||||
#define IMLIB_ENABLE_LAPLACIAN
|
||||
|
||||
// Enable bilateral()
|
||||
#define IMLIB_ENABLE_BILATERAL
|
||||
|
||||
// Enable linpolar()
|
||||
#define IMLIB_ENABLE_LINPOLAR
|
||||
|
||||
// Enable logpolar()
|
||||
#define IMLIB_ENABLE_LOGPOLAR
|
||||
|
||||
// Enable lens_corr()
|
||||
#define IMLIB_ENABLE_LENS_CORR
|
||||
|
||||
// Enable rotation_corr()
|
||||
#define IMLIB_ENABLE_ROTATION_CORR
|
||||
|
||||
// Enable phasecorrelate()
|
||||
#if defined(IMLIB_ENABLE_ROTATION_CORR)
|
||||
#define IMLIB_ENABLE_FIND_DISPLACEMENT
|
||||
#endif
|
||||
|
||||
// Enable get_similarity()
|
||||
#define IMLIB_ENABLE_GET_SIMILARITY
|
||||
|
||||
// Enable find_lines()
|
||||
#define IMLIB_ENABLE_FIND_LINES
|
||||
|
||||
// Enable find_line_segments()
|
||||
#define IMLIB_ENABLE_FIND_LINE_SEGMENTS
|
||||
|
||||
// Enable find_circles()
|
||||
#define IMLIB_ENABLE_FIND_CIRCLES
|
||||
|
||||
// Enable find_rects()
|
||||
#define IMLIB_ENABLE_FIND_RECTS
|
||||
|
||||
// Enable find_qrcodes() (14 KB)
|
||||
#define IMLIB_ENABLE_QRCODES
|
||||
|
||||
// Enable find_apriltags() (64 KB)
|
||||
#define IMLIB_ENABLE_APRILTAGS
|
||||
#define IMLIB_ENABLE_APRILTAGS_TAG36H11
|
||||
|
||||
// Enable fine find_apriltags() - (8-way connectivity versus 4-way connectivity)
|
||||
// #define IMLIB_ENABLE_FINE_APRILTAGS
|
||||
|
||||
// Enable high res find_apriltags() - uses more RAM
|
||||
// #define IMLIB_ENABLE_HIGH_RES_APRILTAGS
|
||||
|
||||
// Enable find_datamatrices() (26 KB)
|
||||
#define IMLIB_ENABLE_DATAMATRICES
|
||||
|
||||
// Enable find_barcodes() (42 KB)
|
||||
#define IMLIB_ENABLE_BARCODES
|
||||
|
||||
// Enable find_features() and Haar cascades.
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
|
||||
// Enable Tensor Flow
|
||||
#define IMLIB_ENABLE_STAI
|
||||
|
||||
// Enable AGAST.
|
||||
#define IMLIB_ENABLE_AGAST
|
||||
|
||||
// Enable find_template()
|
||||
#define IMLIB_FIND_TEMPLATE
|
||||
|
||||
// Enable find_lbp()
|
||||
#define IMLIB_ENABLE_FIND_LBP
|
||||
|
||||
// Enable find_keypoints()
|
||||
#if defined(IMLIB_ENABLE_FAST) || defined(IMLIB_ENABLE_AGAST)
|
||||
#define IMLIB_ENABLE_FIND_KEYPOINTS
|
||||
#endif
|
||||
|
||||
// Enable load, save and match descriptor
|
||||
#define IMLIB_ENABLE_DESCRIPTOR
|
||||
|
||||
// Enable find_hog()
|
||||
#define IMLIB_ENABLE_HOG
|
||||
|
||||
// Enable selective_search()
|
||||
#define IMLIB_ENABLE_SELECTIVE_SEARCH
|
||||
|
||||
// Enable PNG encoder/decoder
|
||||
#define IMLIB_ENABLE_PNG_ENCODER
|
||||
#define IMLIB_ENABLE_PNG_DECODER
|
||||
|
||||
// Stereo Imaging
|
||||
#define IMLIB_ENABLE_STEREO_DISPARITY
|
||||
|
||||
#endif //__IMLIB_CONFIG_H__
|
||||
5
boards/MPS3_AN547/manifest.py
Normal file
5
boards/MPS3_AN547/manifest.py
Normal file
@ -0,0 +1,5 @@
|
||||
# OpenMV library
|
||||
add_library("openmv-lib", "$(OMV_LIB_DIR)")
|
||||
|
||||
# Libraries
|
||||
require("ml", library="openmv-lib")
|
||||
75
boards/MPS3_AN547/omv_boardconfig.h
Normal file
75
boards/MPS3_AN547/omv_boardconfig.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2025 OpenMV, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Board configuration and pin definitions.
|
||||
*/
|
||||
#ifndef __OMV_BOARDCONFIG_H__
|
||||
#define __OMV_BOARDCONFIG_H__
|
||||
|
||||
// Architecture info
|
||||
#define OMV_BOARD_ARCH "MPS3 AN547" // 33 chars max
|
||||
#define OMV_BOARD_TYPE "M55"
|
||||
|
||||
// JPEG configuration.
|
||||
#define OMV_JPEG_CODEC_ENABLE (0)
|
||||
#define OMV_JPEG_QUALITY_LOW (35)
|
||||
#define OMV_JPEG_QUALITY_HIGH (60)
|
||||
#define OMV_JPEG_QUALITY_THRESHOLD (160 * 120 * 2)
|
||||
|
||||
// UMM heap block size
|
||||
#define OMV_UMM_BLOCK_SIZE 16
|
||||
|
||||
#define OMV_MAIN_MEMORY SRAM1 // Data/BSS memory
|
||||
#define OMV_STACK_MEMORY SRAM1 // stack memory
|
||||
#define OMV_STACK_SIZE (64K)
|
||||
#define OMV_FB_MEMORY SRAM1 // Framebuffer, fb_alloc
|
||||
#define OMV_FB_SIZE (1M) // FB memory: header + QVGA/GS image
|
||||
#define OMV_FB_ALLOC_SIZE (1850K) // minimum fb alloc size
|
||||
#define OMV_GC_BLOCK0_MEMORY SRAM1 // Main GC block
|
||||
#define OMV_GC_BLOCK0_SIZE (1M)
|
||||
#define OMV_SB_SIZE (128K) // IDE JPEG buffer size (header + data).
|
||||
|
||||
// Memory map.
|
||||
#define OMV_ITCM_ORIGIN 0x00000000
|
||||
#define OMV_ITCM_LENGTH 512K
|
||||
|
||||
#define OMV_SRAM1_ORIGIN 0x21000000
|
||||
#define OMV_SRAM1_LENGTH 4M
|
||||
|
||||
#define OMV_FLASH_ISR_ORIGIN 0x00000000
|
||||
#define OMV_FLASH_ISR_LENGTH 4K
|
||||
|
||||
#define OMV_FLASH_TXT_ORIGIN 0x01000000
|
||||
#define OMV_FLASH_TXT_LENGTH 2M
|
||||
|
||||
// CSI configuration.
|
||||
#define OMV_CSI_I2C_ID (0)
|
||||
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_STANDARD)
|
||||
#define OMV_CSI_CLK_SOURCE (OMV_CSI_CLK_SOURCE_TIM)
|
||||
#define OMV_CSI_CLK_FREQUENCY (24000000)
|
||||
#define OMV_CSI_HW_CROP_ENABLE (0)
|
||||
#define OMV_CSI_MAX_DEVICES (3)
|
||||
|
||||
#define OMV_SOFTCSI_ENABLE (1)
|
||||
|
||||
#endif //__OMV_BOARDCONFIG_H__
|
||||
25
boards/MPS3_AN547/omv_boardconfig.mk
Normal file
25
boards/MPS3_AN547/omv_boardconfig.mk
Normal file
@ -0,0 +1,25 @@
|
||||
CPU=cortex-m55
|
||||
FPU=auto
|
||||
PORT=qemu
|
||||
QEMU_MACHINE=mps3-an547
|
||||
OMV_ENABLE_BL=0
|
||||
OMV_LEPTON_SDK_ENABLE=0
|
||||
OMV_BOARD_CFLAGS= -mcmse \
|
||||
-DQEMU_SOC_MPS3 \
|
||||
-DCPU_FREQ_HZ=32000000
|
||||
MICROPY_PY_CSI = 1
|
||||
MICROPY_PY_CSI_NG = 1
|
||||
MICROPY_PY_FIR = 0
|
||||
MICROPY_PY_ULAB = 1
|
||||
MICROPY_PY_WINC1500 = 0
|
||||
MICROPY_PY_DISPLAY = 0
|
||||
MICROPY_PY_TV = 0
|
||||
MICROPY_PY_ML = 1
|
||||
MICROPY_PY_ML_TFLM = 1
|
||||
MICROPY_PY_LWIP = 0
|
||||
MICROPY_PY_SSL = 0
|
||||
MICROPY_PY_SSL_ECDSA_SIGN_ALT = 0
|
||||
MICROPY_SSL_MBEDTLS = 0
|
||||
MICROPY_PY_NETWORK_CYW43 = 0
|
||||
MICROPY_PY_BLUETOOTH = 0
|
||||
MICROPY_BLUETOOTH_NIMBLE = 0
|
||||
6
boards/MPS3_AN547/romfs.json
Normal file
6
boards/MPS3_AN547/romfs.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"0": {
|
||||
"size": "0x20000",
|
||||
"entries": [ ]
|
||||
}
|
||||
}
|
||||
17
boards/MPS3_AN547/ulab_config.h
Normal file
17
boards/MPS3_AN547/ulab_config.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013-2016 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* Ulab config file.
|
||||
*
|
||||
*/
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (0)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
#define ULAB_FFT_IS_NUMPY_COMPATIBLE (0)
|
||||
#endif //__ULAB_CONFIG_H__
|
||||
@ -38,6 +38,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
|
||||
@ -38,6 +38,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_v2_224_small.tflite",
|
||||
@ -32,12 +38,30 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolov8n_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/palm_detection_full_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/hand_landmarks_full_224.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "haar",
|
||||
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
|
||||
|
||||
@ -8,6 +8,12 @@
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_v2_224_small.tflite",
|
||||
@ -20,11 +26,29 @@
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolov8n_192.tflite",
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/palm_detection_full_192.tflite",
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/hand_landmarks_full_224.tflite",
|
||||
"alignment": 32,
|
||||
"profile": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -38,6 +38,12 @@
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/yolo_lc_192.tflite",
|
||||
"alignment": 16,
|
||||
"optimize": "Performance"
|
||||
},
|
||||
{
|
||||
"type": "tflite",
|
||||
"path": "{TOP}/lib/models/blazeface_front_128.tflite",
|
||||
|
||||
@ -21,169 +21,104 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Filesystem helper functions.
|
||||
* Filesystem helper functions using MicroPython VFS interface.
|
||||
*/
|
||||
#include "imlib_config.h"
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/builtin.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
|
||||
#include "omv_common.h"
|
||||
#include "fb_alloc.h"
|
||||
#include "file_utils.h"
|
||||
#define FF_MIN(x, y) (((x) < (y))?(x):(y))
|
||||
|
||||
NORETURN static void ff_read_fail(FIL *fp) {
|
||||
if (fp) {
|
||||
f_close(fp);
|
||||
}
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to read requested bytes!"));
|
||||
}
|
||||
|
||||
NORETURN static void ff_write_fail(FIL *fp) {
|
||||
if (fp) {
|
||||
f_close(fp);
|
||||
}
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to write requested bytes!"));
|
||||
}
|
||||
|
||||
NORETURN static void ff_expect_fail(FIL *fp) {
|
||||
if (fp) {
|
||||
f_close(fp);
|
||||
}
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unexpected value read!"));
|
||||
}
|
||||
|
||||
NORETURN void file_raise_format(FIL *fp) {
|
||||
if (fp) {
|
||||
f_close(fp);
|
||||
}
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported format!"));
|
||||
}
|
||||
|
||||
NORETURN void file_raise_corrupted(FIL *fp) {
|
||||
if (fp) {
|
||||
f_close(fp);
|
||||
}
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("File corrupted!"));
|
||||
}
|
||||
|
||||
NORETURN void file_raise_error(FIL *fp, FRESULT res) {
|
||||
if (fp) {
|
||||
f_close(fp);
|
||||
}
|
||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) file_strerror(res));
|
||||
}
|
||||
|
||||
static FATFS *lookup_path(const TCHAR **path) {
|
||||
mp_vfs_mount_t *fs = mp_vfs_lookup_path(*path, path);
|
||||
if (fs == MP_VFS_NONE || fs == MP_VFS_ROOT) {
|
||||
return NULL;
|
||||
}
|
||||
// here we assume that the mounted device is FATFS
|
||||
return &((fs_user_mount_t *) MP_OBJ_TO_PTR(fs->obj))->fatfs;
|
||||
}
|
||||
|
||||
FRESULT file_ll_open(FIL *fp, const TCHAR *path, BYTE mode) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_open(fs, fp, path, mode);
|
||||
}
|
||||
|
||||
FRESULT file_ll_close(FIL *fp) {
|
||||
return f_close(fp);
|
||||
}
|
||||
|
||||
FRESULT file_ll_read(FIL *fp, void *buff, UINT btr, UINT *br) {
|
||||
return f_read(fp, buff, btr, br);
|
||||
}
|
||||
|
||||
FRESULT file_ll_write(FIL *fp, const void *buff, UINT btw, UINT *bw) {
|
||||
return f_write(fp, buff, btw, bw);
|
||||
}
|
||||
|
||||
FRESULT file_ll_opendir(FF_DIR *dp, const TCHAR *path) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_opendir(fs, dp, path);
|
||||
}
|
||||
|
||||
FRESULT file_ll_stat(const TCHAR *path, FILINFO *fno) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_stat(fs, path, fno);
|
||||
}
|
||||
|
||||
FRESULT file_ll_mkdir(const TCHAR *path) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_mkdir(fs, path);
|
||||
}
|
||||
|
||||
FRESULT file_ll_unlink(const TCHAR *path) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_unlink(fs, path);
|
||||
}
|
||||
|
||||
FRESULT file_ll_rename(const TCHAR *path_old, const TCHAR *path_new) {
|
||||
FATFS *fs_old = lookup_path(&path_old);
|
||||
if (fs_old == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
FATFS *fs_new = lookup_path(&path_new);
|
||||
if (fs_new == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
if (fs_old != fs_new) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_rename(fs_new, path_old, path_new);
|
||||
}
|
||||
|
||||
FRESULT file_ll_touch(const TCHAR *path) {
|
||||
FIL fp;
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
|
||||
if (f_stat(fs, path, NULL) != FR_OK) {
|
||||
f_open(fs, &fp, path, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
// When a sector boundary is encountered while writing a file and there are
|
||||
// more than 512 bytes left to write FatFs will detect that it can bypass
|
||||
// its internal write buffer and pass the data buffer passed to it directly
|
||||
// to the disk write function. However, the disk write function needs the
|
||||
// buffer to be aligned to a 4-byte boundary. FatFs doesn't know this and
|
||||
// will pass an unaligned buffer if we don't fix the issue. To fix this problem
|
||||
// we use a temporary buffer to fix the alignment and to speed everything up.
|
||||
// We use this temporary buffer for both reads and writes. The buffer allows us
|
||||
// to do multi-block reads and writes which significantly speed things up.
|
||||
|
||||
// File buffering support
|
||||
static uint32_t file_buffer_offset = 0;
|
||||
static uint8_t *file_buffer_pointer = 0;
|
||||
static uint32_t file_buffer_size = 0;
|
||||
static uint32_t file_buffer_index = 0;
|
||||
|
||||
static inline void file_cleanup(file_t *fp) {
|
||||
if (fp && fp->fp != MP_OBJ_NULL) {
|
||||
file_buffer_init0();
|
||||
mp_stream_close(fp->fp);
|
||||
fp->fp = MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Error/exception functions
|
||||
NORETURN static void file_read_fail(file_t *fp) {
|
||||
file_cleanup(fp);
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to read requested bytes!"));
|
||||
}
|
||||
|
||||
NORETURN static void file_write_fail(file_t *fp) {
|
||||
file_cleanup(fp);
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to write requested bytes!"));
|
||||
}
|
||||
|
||||
NORETURN static void file_expect_fail(file_t *fp) {
|
||||
file_cleanup(fp);
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unexpected value read!"));
|
||||
}
|
||||
|
||||
NORETURN void file_raise_format(file_t *fp) {
|
||||
file_cleanup(fp);
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported format!"));
|
||||
}
|
||||
|
||||
NORETURN void file_raise_corrupted(file_t *fp) {
|
||||
file_cleanup(fp);
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("File corrupted!"));
|
||||
}
|
||||
|
||||
NORETURN void file_raise_error(file_t *fp, mp_rom_error_text_t msg) {
|
||||
file_cleanup(fp);
|
||||
mp_raise_msg(&mp_type_OSError, msg);
|
||||
}
|
||||
|
||||
// Helper function to perform stream seek
|
||||
static off_t file_seek_helper(file_t *fp, off_t offset, int whence) {
|
||||
int err;
|
||||
const mp_stream_p_t *stream_p = mp_get_stream_raise(fp->fp, MP_STREAM_OP_IOCTL);
|
||||
struct mp_stream_seek_t seek_s;
|
||||
seek_s.offset = offset;
|
||||
seek_s.whence = whence;
|
||||
mp_uint_t res = stream_p->ioctl(fp->fp, MP_STREAM_SEEK, (mp_uint_t) (uintptr_t) &seek_s, &err);
|
||||
if (res == MP_STREAM_ERROR) {
|
||||
file_raise_error(fp, MP_ERROR_TEXT("Seek failed"));
|
||||
}
|
||||
return seek_s.offset;
|
||||
}
|
||||
|
||||
// Helper function to read from stream
|
||||
static size_t file_read_helper(file_t *fp, void *buf, size_t len) {
|
||||
int err;
|
||||
const mp_stream_p_t *stream_p = mp_get_stream_raise(fp->fp, MP_STREAM_OP_READ);
|
||||
mp_uint_t out_sz = stream_p->read(fp->fp, buf, len, &err);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
file_raise_error(fp, MP_ERROR_TEXT("Read failed"));
|
||||
}
|
||||
return out_sz;
|
||||
}
|
||||
|
||||
// Helper function to write to stream
|
||||
static size_t file_write_helper(file_t *fp, const void *buf, size_t len) {
|
||||
int err;
|
||||
const mp_stream_p_t *stream_p = mp_get_stream_raise(fp->fp, MP_STREAM_OP_WRITE);
|
||||
mp_uint_t out_sz = stream_p->write(fp->fp, buf, len, &err);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
file_raise_error(fp, MP_ERROR_TEXT("Write failed"));
|
||||
}
|
||||
return out_sz;
|
||||
}
|
||||
|
||||
void file_buffer_init0() {
|
||||
file_buffer_offset = 0;
|
||||
file_buffer_pointer = 0;
|
||||
@ -191,145 +126,215 @@ void file_buffer_init0() {
|
||||
file_buffer_index = 0;
|
||||
}
|
||||
|
||||
OMV_ATTR_ALWAYS_INLINE static void file_fill(FIL *fp) {
|
||||
if (file_buffer_index == file_buffer_size) {
|
||||
file_buffer_pointer -= file_buffer_offset;
|
||||
file_buffer_size += file_buffer_offset;
|
||||
file_buffer_offset = 0;
|
||||
file_buffer_index = 0;
|
||||
uint32_t file_remaining = f_size(fp) - f_tell(fp);
|
||||
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
||||
UINT bytes;
|
||||
FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
if (bytes != can_do) {
|
||||
ff_read_fail(fp);
|
||||
}
|
||||
void file_buffer_on(file_t *fp) {
|
||||
if (!fp || fp->fp == MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OMV_ATTR_ALWAYS_INLINE static void file_flush(FIL *fp) {
|
||||
if (file_buffer_index == file_buffer_size) {
|
||||
UINT bytes;
|
||||
FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
if (bytes != file_buffer_index) {
|
||||
ff_write_fail(fp);
|
||||
}
|
||||
file_buffer_pointer -= file_buffer_offset;
|
||||
file_buffer_size += file_buffer_offset;
|
||||
file_buffer_offset = 0;
|
||||
file_buffer_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void file_buffer_on(FIL *fp) {
|
||||
file_buffer_offset = f_tell(fp) % 4;
|
||||
file_buffer_pointer = fb_alloc_all(&file_buffer_size, FB_ALLOC_PREFER_SIZE) + file_buffer_offset;
|
||||
off_t current_pos = file_seek_helper(fp, 0, SEEK_CUR);
|
||||
file_buffer_offset = current_pos % 4;
|
||||
file_buffer_pointer = (uint8_t *) fb_alloc_all(&file_buffer_size, FB_ALLOC_PREFER_SIZE) + file_buffer_offset;
|
||||
if (!file_buffer_size) {
|
||||
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("No memory!"));
|
||||
}
|
||||
file_buffer_size -= file_buffer_offset;
|
||||
file_buffer_index = 0;
|
||||
if (fp->flag & FA_READ) {
|
||||
uint32_t file_remaining = f_size(fp) - f_tell(fp);
|
||||
|
||||
if (fp->flags & FA_READ) {
|
||||
// Pre-fill buffer for reading
|
||||
off_t file_end = file_seek_helper(fp, 0, SEEK_END);
|
||||
file_seek_helper(fp, current_pos, SEEK_SET);
|
||||
uint32_t file_remaining = file_end - current_pos;
|
||||
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
||||
UINT bytes;
|
||||
FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
|
||||
size_t bytes = file_read_helper(fp, file_buffer_pointer, can_do);
|
||||
if (bytes != can_do) {
|
||||
ff_read_fail(fp);
|
||||
file_read_fail(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void file_buffer_off(FIL *fp) {
|
||||
if ((fp->flag & FA_WRITE) && file_buffer_index) {
|
||||
UINT bytes;
|
||||
FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
void file_buffer_off(file_t *fp) {
|
||||
// Attempt flush after clearing globals
|
||||
if (file_buffer_index && fp && fp->fp && (fp->flags & FA_WRITE)) {
|
||||
size_t bytes = file_write_helper(fp, file_buffer_pointer, file_buffer_index);
|
||||
if (bytes != file_buffer_index) {
|
||||
ff_write_fail(fp);
|
||||
fb_free();
|
||||
file_write_fail(fp);
|
||||
}
|
||||
}
|
||||
file_buffer_pointer = 0;
|
||||
|
||||
fb_free();
|
||||
file_buffer_init0();
|
||||
}
|
||||
|
||||
void file_open(FIL *fp, const char *path, bool buffered, uint32_t flags) {
|
||||
FRESULT res = file_ll_open(fp, path, flags);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
OMV_ATTR_ALWAYS_INLINE static void file_fill(file_t *fp) {
|
||||
if (file_buffer_index == file_buffer_size) {
|
||||
file_buffer_pointer -= file_buffer_offset;
|
||||
file_buffer_size += file_buffer_offset;
|
||||
file_buffer_offset = 0;
|
||||
file_buffer_index = 0;
|
||||
|
||||
// Calculate remaining bytes in file
|
||||
off_t current_pos = file_seek_helper(fp, 0, SEEK_CUR);
|
||||
off_t file_end = file_seek_helper(fp, 0, SEEK_END);
|
||||
file_seek_helper(fp, current_pos, SEEK_SET);
|
||||
uint32_t file_remaining = file_end - current_pos;
|
||||
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
||||
|
||||
size_t bytes = file_read_helper(fp, file_buffer_pointer, can_do);
|
||||
if (bytes != can_do) {
|
||||
file_read_fail(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OMV_ATTR_ALWAYS_INLINE static void file_flush(file_t *fp) {
|
||||
if (file_buffer_index == file_buffer_size) {
|
||||
size_t bytes = file_write_helper(fp, file_buffer_pointer, file_buffer_index);
|
||||
if (bytes != file_buffer_index) {
|
||||
file_write_fail(fp);
|
||||
}
|
||||
file_buffer_pointer -= file_buffer_offset;
|
||||
file_buffer_size += file_buffer_offset;
|
||||
file_buffer_offset = 0;
|
||||
file_buffer_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void file_open(file_t *fp, const char *path, bool buffered, uint32_t flags) {
|
||||
// Initialize fp to safe state in case open fails
|
||||
fp->fp = MP_OBJ_NULL;
|
||||
fp->flags = 0;
|
||||
|
||||
// Reject unsupported FA_READ | FA_WRITE without creation/append flags
|
||||
// This combination would silently truncate the file (mode "wb")
|
||||
if ((flags & (FA_READ | FA_WRITE)) == (FA_READ | FA_WRITE)) {
|
||||
if (!(flags & (FA_CREATE_ALWAYS | FA_OPEN_APPEND | FA_OPEN_ALWAYS))) {
|
||||
mp_raise_msg(&mp_type_ValueError,
|
||||
MP_ERROR_TEXT("FA_READ|FA_WRITE requires FA_OPEN_ALWAYS or FA_CREATE_ALWAYS"));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert flags to MicroPython mode string
|
||||
const char *mode;
|
||||
if (flags & FA_WRITE) {
|
||||
if (flags & FA_CREATE_ALWAYS) {
|
||||
mode = "wb";
|
||||
} else if (flags & FA_OPEN_APPEND) {
|
||||
mode = "ab";
|
||||
} else if (flags & FA_OPEN_ALWAYS) {
|
||||
mode = "r+b";
|
||||
} else {
|
||||
mode = "wb";
|
||||
}
|
||||
} else {
|
||||
mode = "rb";
|
||||
}
|
||||
|
||||
// Open file using MicroPython VFS
|
||||
mp_obj_t args[2] = {
|
||||
mp_obj_new_str_from_cstr(path),
|
||||
mp_obj_new_str_from_cstr(mode)
|
||||
};
|
||||
fp->fp = mp_vfs_open(MP_ARRAY_SIZE(args), args, (mp_map_t *) &mp_const_empty_map);
|
||||
fp->flags = (uint8_t) flags;
|
||||
|
||||
if (buffered) {
|
||||
file_buffer_on(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void file_close(FIL *fp) {
|
||||
void file_close(file_t *fp) {
|
||||
if (fp && fp->fp != MP_OBJ_NULL) {
|
||||
if (file_buffer_pointer) {
|
||||
file_buffer_off(fp);
|
||||
}
|
||||
mp_stream_close(fp->fp);
|
||||
fp->fp = MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void file_seek(file_t *fp, size_t offset) {
|
||||
if (fp && fp->fp) {
|
||||
file_seek_helper(fp, offset, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
void file_truncate(file_t *fp) {
|
||||
if (!fp || fp->fp == MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Truncate file at current position by calling Python truncate() method
|
||||
// Use getattr to get the truncate method
|
||||
mp_obj_t truncate_str = mp_obj_new_str("truncate", 8);
|
||||
mp_obj_t truncate_method = mp_load_attr(fp->fp, qstr_from_str(mp_obj_str_get_str(truncate_str)));
|
||||
// Call truncate() method with no args (truncates at current position)
|
||||
mp_call_function_0(truncate_method);
|
||||
}
|
||||
|
||||
void file_sync(file_t *fp) {
|
||||
int err;
|
||||
|
||||
if (!fp || fp->fp == MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mp_stream_p_t *stream_p = mp_get_stream_raise(fp->fp, MP_STREAM_OP_WRITE);
|
||||
mp_uint_t res = stream_p->ioctl(fp->fp, MP_STREAM_FLUSH, 0, &err);
|
||||
if (res == MP_STREAM_ERROR) {
|
||||
file_raise_error(fp, MP_ERROR_TEXT("Flush failed"));
|
||||
}
|
||||
}
|
||||
|
||||
size_t file_tell(file_t *fp) {
|
||||
if (file_buffer_pointer) {
|
||||
file_buffer_off(fp);
|
||||
}
|
||||
|
||||
FRESULT res = f_close(fp);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
}
|
||||
|
||||
void file_seek(FIL *fp, UINT offset) {
|
||||
FRESULT res = f_lseek(fp, offset);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
}
|
||||
|
||||
void file_truncate(FIL *fp) {
|
||||
FRESULT res = f_truncate(fp);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
}
|
||||
|
||||
void file_sync(FIL *fp) {
|
||||
FRESULT res = f_sync(fp);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t file_tell(FIL *fp) {
|
||||
if (file_buffer_pointer) {
|
||||
if (fp->flag & FA_READ) {
|
||||
return f_tell(fp) - file_buffer_size + file_buffer_index;
|
||||
off_t stream_pos = file_seek_helper(fp, 0, SEEK_CUR);
|
||||
if (fp->flags & FA_READ) {
|
||||
return stream_pos - file_buffer_size + file_buffer_index;
|
||||
} else {
|
||||
return f_tell(fp) + file_buffer_index;
|
||||
return stream_pos + file_buffer_index;
|
||||
}
|
||||
}
|
||||
return f_tell(fp);
|
||||
return file_seek_helper(fp, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
uint32_t file_size(FIL *fp) {
|
||||
size_t file_size(file_t *fp) {
|
||||
if (file_buffer_pointer) {
|
||||
if (fp->flag & FA_READ) {
|
||||
return f_size(fp);
|
||||
off_t current_pos = file_seek_helper(fp, 0, SEEK_CUR);
|
||||
off_t file_end = file_seek_helper(fp, 0, SEEK_END);
|
||||
file_seek_helper(fp, current_pos, SEEK_SET);
|
||||
|
||||
if (fp->flags & FA_READ) {
|
||||
return file_end;
|
||||
} else {
|
||||
return f_size(fp) + file_buffer_index;
|
||||
return file_end + file_buffer_index;
|
||||
}
|
||||
}
|
||||
return f_size(fp);
|
||||
off_t current_pos = file_seek_helper(fp, 0, SEEK_CUR);
|
||||
off_t file_end = file_seek_helper(fp, 0, SEEK_END);
|
||||
file_seek_helper(fp, current_pos, SEEK_SET);
|
||||
return file_end;
|
||||
}
|
||||
|
||||
void file_read(FIL *fp, void *data, size_t size) {
|
||||
bool file_eof(file_t *fp) {
|
||||
if (file_buffer_pointer && (fp->flags & FA_READ)) {
|
||||
return file_buffer_index >= file_buffer_size;
|
||||
}
|
||||
off_t current_pos = file_seek_helper(fp, 0, SEEK_CUR);
|
||||
off_t file_end = file_seek_helper(fp, 0, SEEK_END);
|
||||
file_seek_helper(fp, current_pos, SEEK_SET);
|
||||
return current_pos >= file_end;
|
||||
}
|
||||
|
||||
void file_read(file_t *fp, void *data, size_t size) {
|
||||
if (!fp || fp->fp == MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
// Skip bytes
|
||||
uint8_t byte;
|
||||
if (file_buffer_pointer) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
@ -338,13 +343,9 @@ void file_read(FIL *fp, void *data, size_t size) {
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
UINT bytes;
|
||||
FRESULT res = f_read(fp, &byte, 1, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
size_t bytes = file_read_helper(fp, &byte, 1);
|
||||
if (bytes != 1) {
|
||||
ff_read_fail(fp);
|
||||
file_read_fail(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -364,101 +365,69 @@ void file_read(FIL *fp, void *data, size_t size) {
|
||||
uint32_t can_do = FF_MIN(size, file_buffer_space_left);
|
||||
memcpy(data, file_buffer_pointer + file_buffer_index, can_do);
|
||||
file_buffer_index += can_do;
|
||||
data += can_do;
|
||||
data = ((uint8_t *) data) + can_do;
|
||||
size -= can_do;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UINT bytes;
|
||||
FRESULT res = f_read(fp, data, size, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
size_t bytes = file_read_helper(fp, data, size);
|
||||
if (bytes != size) {
|
||||
ff_read_fail(fp);
|
||||
file_read_fail(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void file_write(FIL *fp, const void *data, size_t size) {
|
||||
void file_write(file_t *fp, const void *data, size_t size) {
|
||||
if (!fp || fp->fp == MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_buffer_pointer) {
|
||||
// We get a massive speed boost by buffering up as much data as possible
|
||||
// before a write to the SD card. So much so that the time wasted by
|
||||
// all these operations does not cost us.
|
||||
// Buffer writes for performance
|
||||
while (size) {
|
||||
uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index;
|
||||
uint32_t can_do = FF_MIN(size, file_buffer_space_left);
|
||||
memcpy(file_buffer_pointer + file_buffer_index, data, can_do);
|
||||
file_buffer_index += can_do;
|
||||
data += can_do;
|
||||
data = ((const uint8_t *) data) + can_do;
|
||||
size -= can_do;
|
||||
file_flush(fp);
|
||||
}
|
||||
} else {
|
||||
UINT bytes;
|
||||
FRESULT res = f_write(fp, data, size, &bytes);
|
||||
if (res != FR_OK) {
|
||||
file_raise_error(fp, res);
|
||||
}
|
||||
size_t bytes = file_write_helper(fp, data, size);
|
||||
if (bytes != size) {
|
||||
ff_write_fail(fp);
|
||||
file_write_fail(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void file_write_byte(FIL *fp, uint8_t value) {
|
||||
void file_write_byte(file_t *fp, uint8_t value) {
|
||||
file_write(fp, &value, 1);
|
||||
}
|
||||
|
||||
void file_write_short(FIL *fp, uint16_t value) {
|
||||
void file_write_short(file_t *fp, uint16_t value) {
|
||||
file_write(fp, &value, 2);
|
||||
}
|
||||
|
||||
void file_write_long(FIL *fp, uint32_t value) {
|
||||
void file_write_long(file_t *fp, uint32_t value) {
|
||||
file_write(fp, &value, 4);
|
||||
}
|
||||
|
||||
void file_read_check(FIL *fp, const void *data, size_t size) {
|
||||
void file_read_check(file_t *fp, const void *data, size_t size) {
|
||||
if (!fp || fp->fp == MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t buf[16];
|
||||
while (size) {
|
||||
size_t len = OMV_MIN(sizeof(buf), size);
|
||||
file_read(fp, buf, len);
|
||||
if (memcmp(data, buf, len)) {
|
||||
ff_expect_fail(fp);
|
||||
file_expect_fail(fp);
|
||||
}
|
||||
size -= len;
|
||||
data = ((uint8_t *) data) + len;
|
||||
data = ((const uint8_t *) data) + len;
|
||||
}
|
||||
}
|
||||
|
||||
const char *file_strerror(FRESULT res) {
|
||||
static const char *ffs_errors[] = {
|
||||
"Succeeded",
|
||||
"A hard error occurred in the low level disk I/O layer",
|
||||
"Assertion failed",
|
||||
"The physical drive cannot work",
|
||||
"Could not find the file",
|
||||
"Could not find the path",
|
||||
"The path name format is invalid",
|
||||
"Access denied due to prohibited access or directory full",
|
||||
"Access denied due to prohibited access",
|
||||
"The file/directory object is invalid",
|
||||
"The physical drive is write protected",
|
||||
"The logical drive number is invalid",
|
||||
"The volume has no work area",
|
||||
"There is no valid FAT volume",
|
||||
"The f_mkfs() aborted due to any parameter error",
|
||||
"Could not get a grant to access the volume within defined period",
|
||||
"The operation is rejected according to the file sharing policy",
|
||||
"LFN working buffer could not be allocated",
|
||||
"Number of open files > _FS_SHARE",
|
||||
"Given parameter is invalid",
|
||||
};
|
||||
|
||||
if (res > (sizeof(ffs_errors) / sizeof(ffs_errors[0]))) {
|
||||
return "unknown error";
|
||||
} else {
|
||||
return ffs_errors[res];
|
||||
}
|
||||
}
|
||||
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
||||
|
||||
@ -21,48 +21,57 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Filesystem helper functions.
|
||||
* Filesystem helper functions using MicroPython VFS interface.
|
||||
*/
|
||||
#ifndef __FILE_UTILS_H__
|
||||
#define __FILE_UTILS_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <ff.h>
|
||||
void file_raise_format(FIL *fp);
|
||||
void file_raise_corrupted(FIL *fp);
|
||||
void file_raise_error(FIL *fp, FRESULT res);
|
||||
#include <sys/types.h>
|
||||
#include "py/obj.h"
|
||||
|
||||
// These low-level functions/wrappers don't use file buffering,
|
||||
// and they don't raise any exceptions, so they're safe to call
|
||||
// from anywhere.
|
||||
FRESULT file_ll_open(FIL *fp, const TCHAR *path, BYTE mode);
|
||||
FRESULT file_ll_close(FIL *fp);
|
||||
FRESULT file_ll_read(FIL *fp, void *buff, UINT btr, UINT *br);
|
||||
FRESULT file_ll_write(FIL *fp, const void *buff, UINT btw, UINT *bw);
|
||||
FRESULT file_ll_opendir(FF_DIR *dp, const TCHAR *path);
|
||||
FRESULT file_ll_stat(const TCHAR *path, FILINFO *fno);
|
||||
FRESULT file_ll_mkdir(const TCHAR *path);
|
||||
FRESULT file_ll_unlink(const TCHAR *path);
|
||||
FRESULT file_ll_rename(const TCHAR *path_old, const TCHAR *path_new);
|
||||
FRESULT file_ll_touch(const TCHAR *path);
|
||||
// File handle that wraps a MicroPython file object
|
||||
// Replaces FatFS FIL type with VFS-agnostic abstraction
|
||||
typedef struct {
|
||||
mp_obj_t fp; // MicroPython file object
|
||||
uint8_t flags; // Open mode flags (FA_READ, FA_WRITE, etc.)
|
||||
} file_t;
|
||||
|
||||
// File buffer functions.
|
||||
// FatFS-compatible mode flags for backward compatibility
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
// Error/exception functions
|
||||
void file_raise_format(file_t *fp);
|
||||
void file_raise_corrupted(file_t *fp);
|
||||
void file_raise_error(file_t *fp, mp_rom_error_text_t msg);
|
||||
|
||||
// File buffer functions
|
||||
void file_buffer_init0();
|
||||
void file_buffer_on(FIL *fp); // Calls fb_alloc_all()
|
||||
void file_buffer_off(FIL *fp); // Calls fb_free()
|
||||
void file_buffer_on(file_t *fp); // Calls fb_alloc_all()
|
||||
void file_buffer_off(file_t *fp); // Calls fb_free()
|
||||
|
||||
// File operations
|
||||
void file_open(file_t *fp, const char *path, bool buffered, uint32_t flags);
|
||||
void file_close(file_t *fp);
|
||||
void file_seek(file_t *fp, size_t offset);
|
||||
void file_truncate(file_t *fp);
|
||||
void file_sync(file_t *fp);
|
||||
size_t file_tell(file_t *fp);
|
||||
size_t file_size(file_t *fp);
|
||||
bool file_eof(file_t *fp);
|
||||
|
||||
// Buffered read/write operations
|
||||
void file_read(file_t *fp, void *data, size_t size);
|
||||
void file_write(file_t *fp, const void *data, size_t size);
|
||||
void file_write_byte(file_t *fp, uint8_t value);
|
||||
void file_write_short(file_t *fp, uint16_t value);
|
||||
void file_write_long(file_t *fp, uint32_t value);
|
||||
void file_read_check(file_t *fp, const void *data, size_t size);
|
||||
|
||||
void file_open(FIL *fp, const char *path, bool buffered, uint32_t flags);
|
||||
void file_close(FIL *fp);
|
||||
void file_seek(FIL *fp, UINT offset);
|
||||
void file_truncate(FIL *fp);
|
||||
void file_sync(FIL *fp);
|
||||
uint32_t file_tell(FIL *fp);
|
||||
uint32_t file_size(FIL *fp);
|
||||
void file_read(FIL *fp, void *data, size_t size);
|
||||
void file_write(FIL *fp, const void *data, size_t size);
|
||||
void file_write_byte(FIL *fp, uint8_t value);
|
||||
void file_write_short(FIL *fp, uint16_t value);
|
||||
void file_write_long(FIL *fp, uint32_t value);
|
||||
void file_read_check(FIL *fp, const void *data, size_t size);
|
||||
const char *file_strerror(FRESULT res);
|
||||
#endif /* __FILE_UTILS_H__ */
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_BUILD
|
||||
#include <stdlib.h>
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
@ -192,3 +192,4 @@ __attribute__((naked)) void PendSV_Handler(void) {
|
||||
"nlr_jump_ptr: .word nlr_jump\n"
|
||||
);
|
||||
}
|
||||
#endif // QEMU_BUILD
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
*
|
||||
* USB debugger.
|
||||
*/
|
||||
#ifndef QEMU_BUILD
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "py/nlr.h"
|
||||
@ -452,3 +453,4 @@ void usbdbg_control(void *buffer, uint8_t request, uint32_t size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // QEMU_BUILD
|
||||
|
||||
@ -35,7 +35,10 @@
|
||||
#include "omv_i2c.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
static uint32_t step = 0;
|
||||
|
||||
static int reset(omv_csi_t *csi) {
|
||||
step = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -88,7 +91,6 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||
framebuffer_to_image(fb, image);
|
||||
image->pixels = buffer->data;
|
||||
|
||||
static uint32_t step = 0;
|
||||
uint32_t offset = (step++ / 4);
|
||||
|
||||
for (size_t y = 0; y < image->h; y++) {
|
||||
|
||||
@ -30,11 +30,6 @@
|
||||
#include "programmer/programmer.h"
|
||||
#include "spi_flash/include/spi_flash_map.h"
|
||||
|
||||
#define MIN(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
/**
|
||||
* Program firmware to WINC1500 memory.
|
||||
*
|
||||
@ -42,27 +37,22 @@
|
||||
*/
|
||||
int burn_firmware(const char *path)
|
||||
{
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
uint32_t offset = 0;
|
||||
UINT bytes = 0, bytes_out=0;
|
||||
size_t bytes = 0;
|
||||
|
||||
int ret = M2M_ERR_FAIL;
|
||||
uint8_t *buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||
|
||||
if (file_ll_open(&fp, path, FA_READ|FA_OPEN_EXISTING) != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||
|
||||
// Firmware image size
|
||||
uint32_t size = f_size(&fp);
|
||||
uint32_t size = file_size(&fp);
|
||||
|
||||
while (size) {
|
||||
// Read a chuck (max FLASH_SECTOR_SZ bytes).
|
||||
bytes = MIN(size, FLASH_SECTOR_SZ);
|
||||
if (file_ll_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) {
|
||||
printf("burn_firmware: file read error!\n");
|
||||
goto error;
|
||||
}
|
||||
file_read(&fp, buf, bytes);
|
||||
|
||||
// Write firmware sector to the WINC1500 memory.
|
||||
if (programmer_write_firmware_image(buf, offset, bytes) != M2M_SUCCESS) {
|
||||
@ -78,7 +68,7 @@ int burn_firmware(const char *path)
|
||||
|
||||
error:
|
||||
fb_free();
|
||||
file_ll_close(&fp);
|
||||
file_close(&fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -88,29 +78,24 @@ error:
|
||||
*/
|
||||
int verify_firmware(const char *path)
|
||||
{
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
uint32_t offset = 0;
|
||||
UINT bytes = 0, bytes_out=0;
|
||||
size_t bytes = 0;
|
||||
|
||||
int ret = M2M_ERR_FAIL;
|
||||
uint8_t *file_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||
uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||
|
||||
if (file_ll_open(&fp, path, FA_READ|FA_OPEN_EXISTING) != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||
|
||||
// Firmware image size
|
||||
uint32_t size = f_size(&fp);
|
||||
uint32_t size = file_size(&fp);
|
||||
|
||||
while (size) {
|
||||
// Firmware chuck size (max FLASH_SECTOR_SZ bytes).
|
||||
bytes = MIN(size, FLASH_SECTOR_SZ);
|
||||
|
||||
if (file_ll_read(&fp, file_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) {
|
||||
printf("verify_firmware: file read error!\n");
|
||||
goto error;
|
||||
}
|
||||
file_read(&fp, file_buf, bytes);
|
||||
|
||||
if (programmer_read_firmware_image(flash_buf, offset, bytes) != M2M_SUCCESS) {
|
||||
printf("verify_firmware: read access failed on firmware section!\r\n");
|
||||
@ -133,7 +118,7 @@ int verify_firmware(const char *path)
|
||||
error:
|
||||
fb_free();
|
||||
fb_free();
|
||||
file_ll_close(&fp);
|
||||
file_close(&fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -143,16 +128,14 @@ error:
|
||||
*/
|
||||
int dump_firmware(const char *path)
|
||||
{
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
uint32_t offset = 0;
|
||||
UINT bytes = 0, bytes_out=0;
|
||||
size_t bytes = 0;
|
||||
|
||||
int ret = M2M_ERR_FAIL;
|
||||
uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||
|
||||
if (file_ll_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
|
||||
// Firmware image size
|
||||
uint32_t size = FLASH_4M_TOTAL_SZ;
|
||||
@ -166,10 +149,7 @@ int dump_firmware(const char *path)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (file_ll_write(&fp, flash_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) {
|
||||
printf("dump_firmware: file write error!\n");
|
||||
goto error;
|
||||
}
|
||||
file_write(&fp, flash_buf, bytes);
|
||||
|
||||
size -= bytes;
|
||||
offset += bytes;
|
||||
@ -179,6 +159,6 @@ int dump_firmware(const char *path)
|
||||
|
||||
error:
|
||||
fb_free();
|
||||
file_ll_close(&fp);
|
||||
file_close(&fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include "file_utils.h"
|
||||
|
||||
// This function inits the geometry values of an image (opens file).
|
||||
bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs) {
|
||||
bool bmp_read_geometry(file_t *fp, image_t *img, const char *path, bmp_read_settings_t *rs) {
|
||||
file_read_check(fp, "BM", 2);
|
||||
|
||||
uint32_t file_size;
|
||||
@ -177,7 +177,7 @@ bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_setting
|
||||
}
|
||||
|
||||
// This function reads the pixel values of an image.
|
||||
void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs) {
|
||||
void bmp_read_pixels(file_t *fp, image_t *img, int n_lines, bmp_read_settings_t *rs) {
|
||||
if (rs->bmp_bpp == 8) {
|
||||
if ((rs->bmp_h < 0) && (rs->bmp_w >= 0) && (img->w == rs->bmp_row_bytes)) {
|
||||
file_read(fp, img->pixels, n_lines * img->w);
|
||||
@ -264,7 +264,7 @@ void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs
|
||||
}
|
||||
|
||||
void bmp_read(image_t *img, const char *path) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
bmp_read_settings_t rs;
|
||||
file_open(&fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||
bmp_read_geometry(&fp, img, path, &rs);
|
||||
@ -275,7 +275,7 @@ void bmp_read(image_t *img, const char *path) {
|
||||
file_close(&fp);
|
||||
}
|
||||
|
||||
static void bmp_write_header(FIL *fp, uint32_t header_size, uint32_t data_size,
|
||||
static void bmp_write_header(file_t *fp, uint32_t header_size, uint32_t data_size,
|
||||
uint32_t bpp, uint32_t ncomp, rectangle_t *r) {
|
||||
// File Header (14 bytes)
|
||||
file_write(fp, "BM", 2);
|
||||
@ -299,7 +299,7 @@ void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("No intersection!"));
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
file_open(&fp, path, true, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
#include "file_utils.h"
|
||||
#define BLOCK_SIZE (126) // (2^7) - 2 // (DO NOT CHANGE!)
|
||||
|
||||
void gif_open(FIL *fp, int width, int height, bool color, bool loop) {
|
||||
void gif_open(file_t *fp, int width, int height, bool color, bool loop) {
|
||||
file_buffer_on(fp);
|
||||
|
||||
file_write(fp, "GIF89a", 6);
|
||||
@ -60,7 +60,7 @@ void gif_open(FIL *fp, int width, int height, bool color, bool loop) {
|
||||
file_buffer_off(fp);
|
||||
}
|
||||
|
||||
void gif_add_frame(FIL *fp, image_t *img, uint16_t delay) {
|
||||
void gif_add_frame(file_t *fp, image_t *img, uint16_t delay) {
|
||||
file_buffer_on(fp);
|
||||
|
||||
if (delay) {
|
||||
@ -125,7 +125,7 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay) {
|
||||
file_buffer_off(fp);
|
||||
}
|
||||
|
||||
void gif_close(FIL *fp) {
|
||||
void gif_close(file_t *fp) {
|
||||
file_write_byte(fp, ';');
|
||||
file_close(fp);
|
||||
}
|
||||
|
||||
@ -634,7 +634,7 @@ static save_image_format_t imblib_parse_extension(image_t *img, const char *path
|
||||
return FORMAT_DONT_CARE;
|
||||
}
|
||||
|
||||
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs) {
|
||||
bool imlib_read_geometry(file_t *fp, image_t *img, const char *path, img_read_settings_t *rs) {
|
||||
char magic[4];
|
||||
file_open(fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||
file_read(fp, &magic, 4);
|
||||
@ -675,7 +675,7 @@ bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_setti
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
void imlib_load_image(image_t *img, const char *path) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
char magic[4];
|
||||
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||
file_read(&fp, &magic, 4);
|
||||
@ -710,7 +710,7 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual
|
||||
ppm_write_subimg(img, path, roi);
|
||||
break;
|
||||
case FORMAT_RAW: {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
file_write(&fp, img->pixels, img->w * img->h);
|
||||
file_close(&fp);
|
||||
@ -733,7 +733,7 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual
|
||||
png_write(img, new_path);
|
||||
fb_free();
|
||||
} else if (IM_IS_BAYER(img)) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
char *new_path = strcat(strcpy(fb_alloc(strlen(path) + 5, FB_ALLOC_NO_HINT), path), ".raw");
|
||||
file_open(&fp, new_path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
file_write(&fp, img->pixels, img->w * img->h);
|
||||
|
||||
@ -1224,12 +1224,12 @@ uint16_t imlib_lab_to_rgb(uint8_t l, int8_t a, int8_t b);
|
||||
uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v);
|
||||
|
||||
/* Image file functions */
|
||||
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs);
|
||||
void ppm_read_pixels(FIL *fp, image_t *img, int n_lines, ppm_read_settings_t *rs);
|
||||
void ppm_read_geometry(file_t *fp, image_t *img, const char *path, ppm_read_settings_t *rs);
|
||||
void ppm_read_pixels(file_t *fp, image_t *img, int n_lines, ppm_read_settings_t *rs);
|
||||
void ppm_read(image_t *img, const char *path);
|
||||
void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r);
|
||||
bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs);
|
||||
void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs);
|
||||
bool bmp_read_geometry(file_t *fp, image_t *img, const char *path, bmp_read_settings_t *rs);
|
||||
void bmp_read_pixels(file_t *fp, image_t *img, int n_lines, bmp_read_settings_t *rs);
|
||||
void bmp_read(image_t *img, const char *path);
|
||||
void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r);
|
||||
#if (OMV_JPEG_CODEC_ENABLE == 1)
|
||||
@ -1242,33 +1242,33 @@ void jpeg_decompress(image_t *dst, image_t *src);
|
||||
bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc, jpeg_subsampling_t subsampling);
|
||||
bool jpeg_is_valid(image_t *img);
|
||||
int jpeg_clean_trailing_bytes(int bpp, uint8_t *data);
|
||||
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settings_t *rs);
|
||||
void jpeg_read_pixels(FIL *fp, image_t *img);
|
||||
void jpeg_read_geometry(file_t *fp, image_t *img, const char *path, jpg_read_settings_t *rs);
|
||||
void jpeg_read_pixels(file_t *fp, image_t *img);
|
||||
void jpeg_read(image_t *img, const char *path);
|
||||
void jpeg_write(image_t *img, const char *path, int quality);
|
||||
void png_decompress(image_t *dst, image_t *src);
|
||||
bool png_compress(image_t *src, image_t *dst);
|
||||
void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_settings_t *rs);
|
||||
void png_read_pixels(FIL *fp, image_t *img);
|
||||
void png_read_geometry(file_t *fp, image_t *img, const char *path, png_read_settings_t *rs);
|
||||
void png_read_pixels(file_t *fp, image_t *img);
|
||||
void png_read(image_t *img, const char *path);
|
||||
void png_write(image_t *img, const char *path);
|
||||
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs);
|
||||
bool imlib_read_geometry(file_t *fp, image_t *img, const char *path, img_read_settings_t *rs);
|
||||
void imlib_image_operation(image_t *img, const char *path, image_t *other, int scalar, line_op_t op, void *data);
|
||||
void imlib_load_image(image_t *img, const char *path);
|
||||
void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int quality);
|
||||
|
||||
/* GIF functions */
|
||||
void gif_open(FIL *fp, int width, int height, bool color, bool loop);
|
||||
void gif_add_frame(FIL *fp, image_t *img, uint16_t delay);
|
||||
void gif_close(FIL *fp);
|
||||
void gif_open(file_t *fp, int width, int height, bool color, bool loop);
|
||||
void gif_add_frame(file_t *fp, image_t *img, uint16_t delay);
|
||||
void gif_close(file_t *fp);
|
||||
|
||||
/* MJPEG functions */
|
||||
void mjpeg_open(FIL *fp, int width, int height);
|
||||
void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
||||
void mjpeg_open(file_t *fp, int width, int height);
|
||||
void mjpeg_write(file_t *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
||||
image_t *img, int quality, rectangle_t *roi, int rgb_channel, int alpha,
|
||||
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint);
|
||||
void mjpeg_sync(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg);
|
||||
void mjpeg_close(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg);
|
||||
void mjpeg_sync(file_t *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg);
|
||||
void mjpeg_close(file_t *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg);
|
||||
|
||||
/* Point functions */
|
||||
point_t *point_alloc(int16_t x, int16_t y);
|
||||
@ -1332,15 +1332,15 @@ array_t *orb_find_keypoints(image_t *image, bool normalized, int threshold,
|
||||
float scale_factor, int max_keypoints, corner_detector_t corner_detector, rectangle_t *roi);
|
||||
int orb_match_keypoints(array_t *kpts1, array_t *kpts2, int *match, int threshold, rectangle_t *r, point_t *c, int *angle);
|
||||
int orb_filter_keypoints(array_t *kpts, rectangle_t *r, point_t *c);
|
||||
int orb_save_descriptor(FIL *fp, array_t *kpts);
|
||||
int orb_load_descriptor(FIL *fp, array_t *kpts);
|
||||
int orb_save_descriptor(file_t *fp, array_t *kpts);
|
||||
int orb_load_descriptor(file_t *fp, array_t *kpts);
|
||||
float orb_cluster_dist(int cx, int cy, void *kp);
|
||||
|
||||
/* LBP Operator */
|
||||
uint8_t *imlib_lbp_desc(image_t *image, rectangle_t *roi);
|
||||
int imlib_lbp_desc_distance(uint8_t *d0, uint8_t *d1);
|
||||
int imlib_lbp_desc_save(FIL *fp, uint8_t *desc);
|
||||
int imlib_lbp_desc_load(FIL *fp, uint8_t **desc);
|
||||
int imlib_lbp_desc_save(file_t *fp, uint8_t *desc);
|
||||
int imlib_lbp_desc_load(file_t *fp, uint8_t **desc);
|
||||
|
||||
/* Iris detector */
|
||||
void imlib_find_iris(image_t *src, point_t *iris, rectangle_t *roi);
|
||||
|
||||
@ -1307,7 +1307,7 @@ int jpeg_clean_trailing_bytes(int size, uint8_t *data) {
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
// This function inits the geometry values of an image.
|
||||
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settings_t *rs) {
|
||||
void jpeg_read_geometry(file_t *fp, image_t *img, const char *path, jpg_read_settings_t *rs) {
|
||||
for (;;) {
|
||||
uint16_t header;
|
||||
file_read(fp, &header, 2);
|
||||
@ -1336,7 +1336,7 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
|
||||
|
||||
rs->jpg_w = width;
|
||||
rs->jpg_h = height;
|
||||
rs->jpg_size = IMLIB_IMAGE_MAX_SIZE(f_size(fp));
|
||||
rs->jpg_size = IMLIB_IMAGE_MAX_SIZE(file_size(fp));
|
||||
|
||||
img->w = rs->jpg_w;
|
||||
img->h = rs->jpg_h;
|
||||
@ -1344,7 +1344,7 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
|
||||
img->pixfmt = PIXFORMAT_JPEG;
|
||||
return;
|
||||
} else {
|
||||
file_seek(fp, f_tell(fp) + size - 2);
|
||||
file_seek(fp, file_tell(fp) + size - 2);
|
||||
}
|
||||
} else {
|
||||
file_raise_corrupted(fp);
|
||||
@ -1353,13 +1353,13 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
|
||||
}
|
||||
|
||||
// This function reads the pixel values of an image.
|
||||
void jpeg_read_pixels(FIL *fp, image_t *img) {
|
||||
void jpeg_read_pixels(file_t *fp, image_t *img) {
|
||||
file_seek(fp, 0);
|
||||
file_read(fp, img->pixels, img->size);
|
||||
}
|
||||
|
||||
void jpeg_read(image_t *img, const char *path) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
jpg_read_settings_t rs;
|
||||
|
||||
// Do not use file buffering here.
|
||||
@ -1375,7 +1375,7 @@ void jpeg_read(image_t *img, const char *path) {
|
||||
}
|
||||
|
||||
void jpeg_write(image_t *img, const char *path, int quality) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
if (IM_IS_JPEG(img)) {
|
||||
file_write(&fp, img->pixels, img->size);
|
||||
|
||||
@ -104,28 +104,21 @@ int imlib_lbp_desc_distance(uint8_t *d0, uint8_t *d1) {
|
||||
return sum;
|
||||
}
|
||||
|
||||
int imlib_lbp_desc_save(FIL *fp, uint8_t *desc) {
|
||||
UINT bytes;
|
||||
// Write descriptor
|
||||
return file_ll_write(fp, desc, LBP_DESC_SIZE, &bytes);
|
||||
int imlib_lbp_desc_save(file_t *fp, uint8_t *desc) {
|
||||
// Write descriptor using VFS abstraction
|
||||
file_write(fp, desc, LBP_DESC_SIZE);
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
int imlib_lbp_desc_load(FIL *fp, uint8_t **desc) {
|
||||
UINT bytes;
|
||||
FRESULT res = FR_OK;
|
||||
|
||||
int imlib_lbp_desc_load(file_t *fp, uint8_t **desc) {
|
||||
*desc = NULL;
|
||||
uint8_t *hist = m_malloc(LBP_DESC_SIZE);
|
||||
|
||||
// Read descriptor
|
||||
res = file_ll_read(fp, hist, LBP_DESC_SIZE, &bytes);
|
||||
if (res != FR_OK || bytes != LBP_DESC_SIZE) {
|
||||
*desc = NULL;
|
||||
m_free(hist);
|
||||
} else {
|
||||
*desc = hist;
|
||||
}
|
||||
// Read descriptor using VFS abstraction
|
||||
// file_read will raise exception on error
|
||||
file_read(fp, hist, LBP_DESC_SIZE);
|
||||
*desc = hist;
|
||||
|
||||
return res;
|
||||
return 0; // Success
|
||||
}
|
||||
#endif //IMLIB_ENABLE_FIND_LBP
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
#define TIME_SCALE (1000)
|
||||
|
||||
void mjpeg_open(FIL *fp, int width, int height) {
|
||||
void mjpeg_open(file_t *fp, int width, int height) {
|
||||
file_write(fp, "RIFF", 4); // FOURCC fcc; - 0
|
||||
file_write_long(fp, 0); // DWORD cb; size - updated on close - 1
|
||||
file_write(fp, "AVI ", 4); // FOURCC fcc; - 2
|
||||
@ -108,7 +108,7 @@ void mjpeg_open(FIL *fp, int width, int height) {
|
||||
file_write(fp, "movi", 4); // FOURCC fcc; - 55
|
||||
}
|
||||
|
||||
void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
||||
void mjpeg_write(file_t *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
||||
image_t *img, int quality, rectangle_t *roi, int rgb_channel, int alpha,
|
||||
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint) {
|
||||
float xscale = width / ((float) roi->w);
|
||||
@ -213,8 +213,8 @@ void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *byt
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
|
||||
void mjpeg_sync(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||
uint32_t position = f_tell(fp);
|
||||
void mjpeg_sync(file_t *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||
uint32_t position = file_tell(fp);
|
||||
// size of all mjpeg headers and jpegs.
|
||||
uint32_t datasize = (frames * 8) + bytes;
|
||||
// frames_per_second == rate / scale
|
||||
@ -250,7 +250,7 @@ void mjpeg_sync(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||
file_seek(fp, position);
|
||||
}
|
||||
|
||||
void mjpeg_close(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||
void mjpeg_close(file_t *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||
mjpeg_sync(fp, frames, bytes, us_avg);
|
||||
file_close(fp);
|
||||
}
|
||||
|
||||
109
lib/imlib/orb.c
109
lib/imlib/orb.c
@ -706,122 +706,49 @@ int orb_filter_keypoints(array_t *kpts, rectangle_t *r, point_t *c) {
|
||||
}
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
int orb_save_descriptor(FIL *fp, array_t *kpts) {
|
||||
UINT bytes;
|
||||
FRESULT res;
|
||||
|
||||
int orb_save_descriptor(file_t *fp, array_t *kpts) {
|
||||
int kpts_size = array_length(kpts);
|
||||
|
||||
// Write the number of keypoints
|
||||
res = file_ll_write(fp, &kpts_size, sizeof(kpts_size), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kpts_size)) {
|
||||
goto error;
|
||||
}
|
||||
file_write(fp, &kpts_size, sizeof(kpts_size));
|
||||
|
||||
// Write keypoints
|
||||
for (int i = 0; i < kpts_size; i++) {
|
||||
kp_t *kp = array_at(kpts, i);
|
||||
|
||||
// Write X
|
||||
res = file_ll_write(fp, &kp->x, sizeof(kp->x), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->x)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Write Y
|
||||
res = file_ll_write(fp, &kp->y, sizeof(kp->y), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->y)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Write Score
|
||||
res = file_ll_write(fp, &kp->score, sizeof(kp->score), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->score)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Write Octave
|
||||
res = file_ll_write(fp, &kp->octave, sizeof(kp->octave), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->octave)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Write Angle
|
||||
res = file_ll_write(fp, &kp->angle, sizeof(kp->angle), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->angle)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Write descriptor
|
||||
res = file_ll_write(fp, kp->desc, KDESC_SIZE, &bytes);
|
||||
if (res != FR_OK || bytes != KDESC_SIZE) {
|
||||
goto error;
|
||||
}
|
||||
file_write(fp, &kp->x, sizeof(kp->x));
|
||||
file_write(fp, &kp->y, sizeof(kp->y));
|
||||
file_write(fp, &kp->score, sizeof(kp->score));
|
||||
file_write(fp, &kp->octave, sizeof(kp->octave));
|
||||
file_write(fp, &kp->angle, sizeof(kp->angle));
|
||||
file_write(fp, kp->desc, KDESC_SIZE);
|
||||
}
|
||||
|
||||
error:
|
||||
return res;
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
int orb_load_descriptor(FIL *fp, array_t *kpts) {
|
||||
UINT bytes;
|
||||
FRESULT res = FR_OK;
|
||||
|
||||
int orb_load_descriptor(file_t *fp, array_t *kpts) {
|
||||
int kpts_size = 0;
|
||||
|
||||
// Read number of keypoints
|
||||
res = file_ll_read(fp, &kpts_size, sizeof(kpts_size), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kpts_size)) {
|
||||
goto error;
|
||||
}
|
||||
file_read(fp, &kpts_size, sizeof(kpts_size));
|
||||
|
||||
// Read keypoints
|
||||
for (int i = 0; i < kpts_size; i++) {
|
||||
kp_t *kp = m_malloc(sizeof(*kp));
|
||||
kp->matched = 0;
|
||||
|
||||
// Read X
|
||||
res = file_ll_read(fp, &kp->x, sizeof(kp->x), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->x)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Read Y
|
||||
res = file_ll_read(fp, &kp->y, sizeof(kp->y), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->y)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Read Score
|
||||
res = file_ll_read(fp, &kp->score, sizeof(kp->score), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->score)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Read Octave
|
||||
res = file_ll_read(fp, &kp->octave, sizeof(kp->octave), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->octave)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Read Angle
|
||||
res = file_ll_read(fp, &kp->angle, sizeof(kp->angle), &bytes);
|
||||
if (res != FR_OK || bytes != sizeof(kp->angle)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Read descriptor
|
||||
res = file_ll_read(fp, kp->desc, KDESC_SIZE, &bytes);
|
||||
if (res != FR_OK || bytes != KDESC_SIZE) {
|
||||
goto error;
|
||||
}
|
||||
file_read(fp, &kp->x, sizeof(kp->x));
|
||||
file_read(fp, &kp->y, sizeof(kp->y));
|
||||
file_read(fp, &kp->score, sizeof(kp->score));
|
||||
file_read(fp, &kp->octave, sizeof(kp->octave));
|
||||
file_read(fp, &kp->angle, sizeof(kp->angle));
|
||||
file_read(fp, kp->desc, KDESC_SIZE);
|
||||
|
||||
// Add keypoint to array
|
||||
array_push_back(kpts, kp);
|
||||
}
|
||||
|
||||
error:
|
||||
return res;
|
||||
return 0; // Success
|
||||
}
|
||||
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
||||
|
||||
|
||||
@ -256,7 +256,7 @@ void png_decompress(image_t *dst, image_t *src) {
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
// This function inits the geometry values of an image.
|
||||
void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_settings_t *rs) {
|
||||
void png_read_geometry(file_t *fp, image_t *img, const char *path, png_read_settings_t *rs) {
|
||||
uint32_t header;
|
||||
file_seek(fp, 12); // start of IHDR
|
||||
file_read(fp, &header, 4);
|
||||
@ -270,7 +270,7 @@ void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_setting
|
||||
|
||||
rs->png_w = width;
|
||||
rs->png_h = height;
|
||||
rs->png_size = IMLIB_IMAGE_MAX_SIZE(f_size(fp));
|
||||
rs->png_size = IMLIB_IMAGE_MAX_SIZE(file_size(fp));
|
||||
|
||||
img->w = rs->png_w;
|
||||
img->h = rs->png_h;
|
||||
@ -282,13 +282,13 @@ void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_setting
|
||||
}
|
||||
|
||||
// This function reads the pixel values of an image.
|
||||
void png_read_pixels(FIL *fp, image_t *img) {
|
||||
void png_read_pixels(file_t *fp, image_t *img) {
|
||||
file_seek(fp, 0);
|
||||
file_read(fp, img->pixels, img->size);
|
||||
}
|
||||
|
||||
void png_read(image_t *img, const char *path) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
png_read_settings_t rs;
|
||||
|
||||
// Do not use file buferring here.
|
||||
@ -305,7 +305,7 @@ void png_read(image_t *img, const char *path) {
|
||||
}
|
||||
|
||||
void png_write(image_t *img, const char *path) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
if (img->pixfmt == PIXFORMAT_PNG) {
|
||||
file_write(&fp, img->pixels, img->size);
|
||||
|
||||
@ -38,7 +38,7 @@ static void read_int_reset(ppm_read_settings_t *rs) {
|
||||
rs->read_int_c_valid = false;
|
||||
}
|
||||
|
||||
static void read_int(FIL *fp, uint32_t *i, ppm_read_settings_t *rs) {
|
||||
static void read_int(file_t *fp, uint32_t *i, ppm_read_settings_t *rs) {
|
||||
enum {
|
||||
EAT_WHITESPACE, EAT_COMMENT, EAT_NUMBER
|
||||
} mode = EAT_WHITESPACE;
|
||||
@ -73,7 +73,7 @@ static void read_int(FIL *fp, uint32_t *i, ppm_read_settings_t *rs) {
|
||||
}
|
||||
|
||||
// This function inits the geometry values of an image.
|
||||
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs) {
|
||||
void ppm_read_geometry(file_t *fp, image_t *img, const char *path, ppm_read_settings_t *rs) {
|
||||
read_int_reset(rs);
|
||||
file_read_check(fp, "P", 1);
|
||||
file_read(fp, &rs->ppm_fmt, 1);
|
||||
@ -99,7 +99,7 @@ void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_setting
|
||||
}
|
||||
|
||||
// This function reads the pixel values of an image.
|
||||
void ppm_read_pixels(FIL *fp, image_t *img, int n_lines, ppm_read_settings_t *rs) {
|
||||
void ppm_read_pixels(file_t *fp, image_t *img, int n_lines, ppm_read_settings_t *rs) {
|
||||
if (rs->ppm_fmt == '2') {
|
||||
for (int i = 0; i < n_lines; i++) {
|
||||
for (int j = 0; j < img->w; j++) {
|
||||
@ -134,7 +134,7 @@ void ppm_read_pixels(FIL *fp, image_t *img, int n_lines, ppm_read_settings_t *rs
|
||||
}
|
||||
|
||||
void ppm_read(image_t *img, const char *path) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
ppm_read_settings_t rs;
|
||||
|
||||
file_open(&fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||
@ -153,7 +153,7 @@ void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("No intersection!"));
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
file_open(&fp, path, true, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit f66a66d4d7b42cac78f9064a8ed12b54459a236f
|
||||
Subproject commit 46b10ee22a4ca687b6bce36a741c5d8a9fc33ef0
|
||||
BIN
lib/models/hand_landmarks_full_224.tflite
Normal file
BIN
lib/models/hand_landmarks_full_224.tflite
Normal file
Binary file not shown.
BIN
lib/models/palm_detection_full_192.tflite
Normal file
BIN
lib/models/palm_detection_full_192.tflite
Normal file
Binary file not shown.
BIN
lib/models/yolo_lc_192.tflite
Normal file
BIN
lib/models/yolo_lc_192.tflite
Normal file
Binary file not shown.
1
lib/models/yolo_lc_192.txt
Normal file
1
lib/models/yolo_lc_192.txt
Normal file
@ -0,0 +1 @@
|
||||
person
|
||||
BIN
lib/models/yolov8n_192.tflite
Normal file
BIN
lib/models/yolov8n_192.tflite
Normal file
Binary file not shown.
1
lib/models/yolov8n_192.txt
Normal file
1
lib/models/yolov8n_192.txt
Normal file
@ -0,0 +1 @@
|
||||
person
|
||||
@ -45,7 +45,7 @@ typedef struct py_gif_obj {
|
||||
uint32_t height;
|
||||
bool color;
|
||||
bool loop;
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
} py_gif_obj_t;
|
||||
|
||||
static void py_gif_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
|
||||
@ -48,12 +48,12 @@ image_t *py_helper_arg_to_image(const mp_obj_t arg, uint32_t flags) {
|
||||
if ((flags & ARG_IMAGE_ALLOC) && MP_OBJ_IS_STR(arg)) {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
const char *path = mp_obj_str_get_str(arg);
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
image = m_malloc(sizeof(image_t));
|
||||
img_read_settings_t rs;
|
||||
imlib_read_geometry(&fp, image, path, &rs);
|
||||
file_close(&fp);
|
||||
image->data = fb_alloc(image_size(image), FB_ALLOC_CACHE_ALIGN);
|
||||
image_alloc(image, image_size(image));
|
||||
imlib_load_image(image, path);
|
||||
#else
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
|
||||
@ -619,4 +619,6 @@ void py_helper_set_to_framebuffer(image_t *img) {
|
||||
|
||||
framebuffer_from_image(fb, img);
|
||||
img->data = buffer->data;
|
||||
|
||||
framebuffer_release(fb, FB_FLAG_FREE);
|
||||
}
|
||||
|
||||
@ -6188,7 +6188,7 @@ mp_obj_t py_image_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw
|
||||
|
||||
if (mp_obj_is_str(args[ARG_arg].u_obj)) {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
img_read_settings_t rs;
|
||||
const char *path = mp_obj_str_get_str(args[ARG_arg].u_obj);
|
||||
|
||||
@ -6911,8 +6911,7 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_ca
|
||||
#if defined(IMLIB_ENABLE_DESCRIPTOR)
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
mp_obj_t py_image_load_descriptor(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
FIL fp;
|
||||
FRESULT res = FR_OK;
|
||||
file_t fp;
|
||||
|
||||
uint32_t desc_type;
|
||||
mp_obj_t desc = mp_const_none;
|
||||
@ -6930,10 +6929,8 @@ mp_obj_t py_image_load_descriptor(size_t n_args, const mp_obj_t *args, mp_map_t
|
||||
py_lbp_obj_t *lbp = m_new_obj(py_lbp_obj_t);
|
||||
lbp->base.type = &py_lbp_type;
|
||||
|
||||
res = imlib_lbp_desc_load(&fp, &lbp->hist);
|
||||
if (res == FR_OK) {
|
||||
desc = lbp;
|
||||
}
|
||||
imlib_lbp_desc_load(&fp, &lbp->hist);
|
||||
desc = lbp;
|
||||
break;
|
||||
}
|
||||
#endif //IMLIB_ENABLE_FIND_LBP
|
||||
@ -6942,29 +6939,27 @@ mp_obj_t py_image_load_descriptor(size_t n_args, const mp_obj_t *args, mp_map_t
|
||||
array_t *kpts = NULL;
|
||||
array_alloc(&kpts, m_free);
|
||||
|
||||
res = orb_load_descriptor(&fp, kpts);
|
||||
if (res == FR_OK) {
|
||||
// Return keypoints MP object
|
||||
py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t);
|
||||
kp_obj->base.type = &py_kp_type;
|
||||
kp_obj->kpts = kpts;
|
||||
kp_obj->threshold = 10;
|
||||
kp_obj->normalized = false;
|
||||
desc = kp_obj;
|
||||
}
|
||||
orb_load_descriptor(&fp, kpts);
|
||||
|
||||
// Return keypoints MP object
|
||||
py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t);
|
||||
kp_obj->base.type = &py_kp_type;
|
||||
kp_obj->kpts = kpts;
|
||||
kp_obj->threshold = 10;
|
||||
kp_obj->normalized = false;
|
||||
desc = kp_obj;
|
||||
break;
|
||||
}
|
||||
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
||||
default:
|
||||
// Unsupported descriptor type
|
||||
desc = mp_const_none;
|
||||
break;
|
||||
}
|
||||
|
||||
file_close(&fp);
|
||||
|
||||
// File read error
|
||||
if (res != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) file_strerror(res));
|
||||
}
|
||||
|
||||
// If no file error and descriptor is still none, then it's not supported.
|
||||
// If descriptor is still none, then it's not supported.
|
||||
if (desc == mp_const_none) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Descriptor type is not supported"));
|
||||
}
|
||||
@ -6973,8 +6968,7 @@ mp_obj_t py_image_load_descriptor(size_t n_args, const mp_obj_t *args, mp_map_t
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_descriptor_obj, 1, py_image_load_descriptor);
|
||||
|
||||
mp_obj_t py_image_save_descriptor(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
FIL fp;
|
||||
FRESULT res = FR_OK;
|
||||
file_t fp;
|
||||
|
||||
uint32_t desc_type;
|
||||
const char *path = mp_obj_str_get_str(args[1]);
|
||||
@ -7005,26 +6999,20 @@ mp_obj_t py_image_save_descriptor(size_t n_args, const mp_obj_t *args, mp_map_t
|
||||
#if defined(IMLIB_ENABLE_FIND_LBP)
|
||||
case DESC_LBP: {
|
||||
py_lbp_obj_t *lbp = ((py_lbp_obj_t *) args[0]);
|
||||
res = imlib_lbp_desc_save(&fp, lbp->hist);
|
||||
imlib_lbp_desc_save(&fp, lbp->hist);
|
||||
break;
|
||||
}
|
||||
#endif //IMLIB_ENABLE_FIND_LBP
|
||||
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
||||
case DESC_ORB: {
|
||||
py_kp_obj_t *kpts = ((py_kp_obj_t *) args[0]);
|
||||
res = orb_save_descriptor(&fp, kpts->kpts);
|
||||
orb_save_descriptor(&fp, kpts->kpts);
|
||||
break;
|
||||
}
|
||||
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
||||
}
|
||||
|
||||
// ignore unsupported descriptors when saving
|
||||
file_close(&fp);
|
||||
|
||||
// File write error
|
||||
if (res != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) file_strerror(res));
|
||||
}
|
||||
return mp_const_true;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_descriptor_obj, 2, py_image_save_descriptor);
|
||||
@ -7116,16 +7104,12 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 2, py_image_mat
|
||||
|
||||
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS) && defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
array_t *kpts = orb_find_keypoints(img, false, 20, 1.5f, 100, CORNER_AGAST, roi);
|
||||
if (array_length(kpts)) {
|
||||
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
FRESULT res = orb_save_descriptor(&fp, kpts);
|
||||
orb_save_descriptor(&fp, kpts);
|
||||
file_close(&fp);
|
||||
// File write error
|
||||
if (res != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) file_strerror(res));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ typedef struct py_imageio_obj {
|
||||
union {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
struct {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
int version;
|
||||
};
|
||||
#endif
|
||||
@ -113,7 +113,7 @@ static void py_imageio_print(const mp_print_t *print, mp_obj_t self, mp_print_ki
|
||||
#endif
|
||||
(stream->type == IMAGE_IO_FILE_STREAM) ? 0 : stream->size,
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
(stream->type == IMAGE_IO_FILE_STREAM) ? f_size(&stream->fp) : (stream->count * stream->size));
|
||||
(stream->type == IMAGE_IO_FILE_STREAM) ? file_size(&stream->fp) : (stream->count * stream->size));
|
||||
#else
|
||||
stream->count * stream->size);
|
||||
#endif
|
||||
@ -169,7 +169,7 @@ static mp_obj_t py_imageio_size(mp_obj_t self) {
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||
return mp_obj_new_int(f_size(&stream->fp));
|
||||
return mp_obj_new_int(file_size(&stream->fp));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -187,7 +187,7 @@ static mp_obj_t py_imageio_write(mp_obj_t self, mp_obj_t img_obj) {
|
||||
if (0) {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||
FIL *fp = &stream->fp;
|
||||
file_t *fp = &stream->fp;
|
||||
|
||||
file_write_long(fp, elapsed_ms);
|
||||
file_write_long(fp, image->w);
|
||||
@ -224,7 +224,7 @@ static mp_obj_t py_imageio_write(mp_obj_t self, mp_obj_t img_obj) {
|
||||
|
||||
// Seeking to the middle of a file and writing data corrupts the remainder of the file. So,
|
||||
// truncate the rest of the file when this happens to prevent crashing because of this.
|
||||
if (!f_eof(fp)) {
|
||||
if (!file_eof(fp)) {
|
||||
file_truncate(fp);
|
||||
}
|
||||
|
||||
@ -273,9 +273,9 @@ static void int_py_imageio_pause(py_imageio_obj_t *stream, bool pause) {
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
static void int_py_imageio_read_chunk(py_imageio_obj_t *stream, image_t *image, bool pause) {
|
||||
FIL *fp = &stream->fp;
|
||||
file_t *fp = &stream->fp;
|
||||
|
||||
if (f_eof(fp)) {
|
||||
if (file_eof(fp)) {
|
||||
mp_raise_msg(&mp_type_EOFError, MP_ERROR_TEXT("End of stream"));
|
||||
}
|
||||
|
||||
@ -333,9 +333,9 @@ static mp_obj_t py_imageio_read(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||
if (0) {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||
FIL *fp = &stream->fp;
|
||||
file_t *fp = &stream->fp;
|
||||
|
||||
if (f_eof(fp)) {
|
||||
if (file_eof(fp)) {
|
||||
if (args[ARG_loop].u_bool == false) {
|
||||
return mp_const_none;
|
||||
}
|
||||
@ -344,7 +344,7 @@ static mp_obj_t py_imageio_read(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||
|
||||
stream->offset = 0;
|
||||
|
||||
if (f_eof(fp)) {
|
||||
if (file_eof(fp)) {
|
||||
// Empty file
|
||||
return mp_const_none;
|
||||
}
|
||||
@ -372,7 +372,7 @@ static mp_obj_t py_imageio_read(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||
if (0) {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||
FIL *fp = &stream->fp;
|
||||
file_t *fp = &stream->fp;
|
||||
file_read(fp, image.data, size);
|
||||
|
||||
// Check if original byte reversed data.
|
||||
@ -423,7 +423,7 @@ static mp_obj_t py_imageio_seek(mp_obj_t self, mp_obj_t offs) {
|
||||
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||
FIL *fp = &stream->fp;
|
||||
file_t *fp = &stream->fp;
|
||||
file_seek(fp, MAGIC_SIZE); // skip past the file header
|
||||
|
||||
for (int i = 0; i < offset; i++) {
|
||||
@ -435,7 +435,7 @@ static mp_obj_t py_imageio_seek(mp_obj_t self, mp_obj_t offs) {
|
||||
size += ALIGN_SIZE - (size % ALIGN_SIZE);
|
||||
}
|
||||
|
||||
file_seek(fp, f_tell(fp) + size);
|
||||
file_seek(fp, file_tell(fp) + size);
|
||||
}
|
||||
|
||||
if (stream->offset >= stream->count) {
|
||||
@ -464,7 +464,12 @@ static mp_obj_t py_imageio_sync(mp_obj_t self) {
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_imageio_sync_obj, py_imageio_sync);
|
||||
|
||||
static mp_obj_t py_imageio_close(mp_obj_t self) {
|
||||
py_imageio_obj_t *stream = py_imageio_obj(self);
|
||||
py_imageio_obj_t *stream = MP_OBJ_TO_PTR(self);
|
||||
|
||||
if (stream->closed) {
|
||||
// Already closed
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
@ -477,7 +482,7 @@ static mp_obj_t py_imageio_close(mp_obj_t self) {
|
||||
|
||||
stream->closed = true;
|
||||
|
||||
return self;
|
||||
return mp_const_none;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_imageio_close_obj, py_imageio_close);
|
||||
|
||||
@ -490,47 +495,20 @@ static mp_obj_t py_imageio_make_new(const mp_obj_type_t *type, size_t n_args, si
|
||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||
} else if (mp_obj_is_str(args[0])) {
|
||||
// File Stream I/O
|
||||
FIL *fp = &stream->fp;
|
||||
file_t *fp = &stream->fp;
|
||||
stream->type = IMAGE_IO_FILE_STREAM;
|
||||
stream->count = 0;
|
||||
|
||||
char mode = mp_obj_str_get_str(args[1])[0];
|
||||
|
||||
if ((mode == 'W') || (mode == 'w')) {
|
||||
file_open(fp, mp_obj_str_get_str(args[0]), false, FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
|
||||
if (mode == 'w') {
|
||||
file_open(fp, mp_obj_str_get_str(args[0]), false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
const char string[] = "OMV IMG STR V2.0";
|
||||
stream->version = NEW_PIXFORMAT_VER;
|
||||
|
||||
// Overwrite if file is too small.
|
||||
if (f_size(fp) < MAGIC_SIZE) {
|
||||
file_write(fp, string, sizeof(string) - 1); // exclude null terminator
|
||||
} else {
|
||||
uint8_t version_hi, period, version_lo;
|
||||
char temp[sizeof(string) - 3] = {};
|
||||
file_read(fp, temp, sizeof(temp) - 1);
|
||||
file_read(fp, &version_hi, 1);
|
||||
file_read(fp, &period, 1);
|
||||
file_read(fp, &version_lo, 1);
|
||||
int version = ((version_hi - '0') * 10) + (version_lo - '0');
|
||||
|
||||
// Overwrite if file magic does not match.
|
||||
if (strcmp(string, temp)
|
||||
|| (period != ((uint8_t) '.'))
|
||||
|| (version != ORIGINAL_VER)
|
||||
|| (version != RGB565_FIXED_VER)
|
||||
|| (version != NEW_PIXFORMAT_VER)) {
|
||||
file_seek(fp, 0);
|
||||
file_write(fp, string, sizeof(string) - 1); // exclude null terminator
|
||||
} else {
|
||||
file_close(fp);
|
||||
mode = 'R';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode == 'R') || (mode == 'r')) {
|
||||
file_write(fp, string, sizeof(string) - 1); // exclude null terminator
|
||||
} else if (mode == 'r') {
|
||||
uint8_t version_hi, version_lo;
|
||||
file_open(fp, mp_obj_str_get_str(args[0]), false, FA_READ | FA_WRITE | FA_OPEN_EXISTING);
|
||||
file_open(fp, mp_obj_str_get_str(args[0]), false, FA_READ | FA_OPEN_EXISTING);
|
||||
file_read_check(fp, "OMV IMG STR ", 12); // Magic
|
||||
file_read_check(fp, "V", 1);
|
||||
file_read(fp, &version_hi, 1);
|
||||
@ -545,7 +523,7 @@ static mp_obj_t py_imageio_make_new(const mp_obj_type_t *type, size_t n_args, si
|
||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected version V1.0, V1.1, or V2.0"));
|
||||
}
|
||||
} else if ((mode != 'W') && (mode != 'w')) {
|
||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid stream mode, expected 'R/r' or 'W/w'"));
|
||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid stream mode, expected 'r' or 'w'"));
|
||||
}
|
||||
#endif
|
||||
} else if (mp_obj_is_type(args[0], &mp_type_tuple)) {
|
||||
|
||||
@ -50,7 +50,7 @@ typedef struct py_mjpeg_obj {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
bool closed;
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
} py_mjpeg_obj_t;
|
||||
|
||||
static void py_mjpeg_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
@ -60,7 +60,7 @@ static void py_mjpeg_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
|
||||
self->width,
|
||||
self->height,
|
||||
self->frames,
|
||||
f_size(&self->fp));
|
||||
file_size(&self->fp));
|
||||
}
|
||||
|
||||
static mp_obj_t py_mjpeg_is_closed(mp_obj_t self_in) {
|
||||
@ -89,7 +89,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_count_obj, py_mjpeg_count);
|
||||
|
||||
static mp_obj_t py_mjpeg_size(mp_obj_t self_in) {
|
||||
py_mjpeg_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_int(f_size(&self->fp));
|
||||
return mp_obj_new_int(file_size(&self->fp));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_size_obj, py_mjpeg_size);
|
||||
|
||||
|
||||
@ -262,16 +262,17 @@ static mp_obj_t py_ml_model_predict(size_t n_args, const mp_obj_t *pos_args, mp_
|
||||
}
|
||||
|
||||
bool callback = args[ARG_callback].u_obj != mp_const_none;
|
||||
bool postprocess = model->postprocess != mp_const_none || callback;
|
||||
|
||||
py_ml_process_input(model, pos_args[1]);
|
||||
ml_backend_run_inference(model);
|
||||
|
||||
mp_obj_t output = py_ml_process_output(model, !callback);
|
||||
mp_obj_t output = py_ml_process_output(model, !postprocess);
|
||||
|
||||
if (callback) {
|
||||
if (postprocess) {
|
||||
// Pass model, inputs, outputs to the post-processing callback.
|
||||
mp_obj_t fargs[3] = { MP_OBJ_FROM_PTR(model), pos_args[1], output };
|
||||
output = mp_call_function_n_kw(args[ARG_callback].u_obj, 3, 0, fargs);
|
||||
output = mp_call_function_n_kw(callback ? args[ARG_callback].u_obj : model->postprocess, 3, 0, fargs);
|
||||
}
|
||||
|
||||
return output;
|
||||
@ -313,6 +314,9 @@ static void py_ml_model_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
case MP_QSTR_output_zero_point:
|
||||
dest[0] = MP_OBJ_FROM_PTR(self->output_zero_point);
|
||||
break;
|
||||
case MP_QSTR_postprocess:
|
||||
dest[0] = self->postprocess;
|
||||
break;
|
||||
default:
|
||||
// Continue lookup in locals_dict.
|
||||
dest[1] = MP_OBJ_SENTINEL;
|
||||
@ -322,10 +326,11 @@ static void py_ml_model_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
}
|
||||
|
||||
mp_obj_t py_ml_model_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_path, ARG_load_to_fb };
|
||||
enum { ARG_path, ARG_load_to_fb, ARG_postprocess };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_path, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_load_to_fb, MP_ARG_REQUIRED | MP_ARG_BOOL },
|
||||
{ MP_QSTR_postprocess, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
@ -334,6 +339,7 @@ mp_obj_t py_ml_model_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
|
||||
|
||||
//const char *path = mp_obj_str_get_str(args[ARG_path].u_obj);
|
||||
py_ml_model_obj_t *model = mp_obj_malloc_with_finaliser(py_ml_model_obj_t, &py_ml_model_type);
|
||||
model->postprocess = args[ARG_postprocess].u_obj;
|
||||
|
||||
#if MICROPY_VFS
|
||||
mp_obj_t file_args[2] = {
|
||||
|
||||
@ -51,6 +51,7 @@ typedef struct py_ml_model_obj {
|
||||
mp_obj_tuple_t *output_scale;
|
||||
mp_obj_tuple_t *output_zero_point;
|
||||
mp_obj_tuple_t *output_dtype;
|
||||
mp_obj_t postprocess; // Post-processing object.
|
||||
void *state; // Private context for the backend.
|
||||
} py_ml_model_obj_t;
|
||||
|
||||
|
||||
@ -55,7 +55,8 @@ static mp_obj_t py_omv_board_type() {
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_board_type_obj, py_omv_board_type);
|
||||
|
||||
static mp_obj_t py_omv_board_id() {
|
||||
char str[25];
|
||||
char str[25] = {0};
|
||||
#ifdef OMV_BOARD_UID_ADDR
|
||||
snprintf(str, 25, "%08X%08X%08X",
|
||||
#if (OMV_BOARD_UID_SIZE == 2)
|
||||
0U,
|
||||
@ -64,6 +65,7 @@ static mp_obj_t py_omv_board_id() {
|
||||
#endif
|
||||
*((unsigned int *) (OMV_BOARD_UID_ADDR + OMV_BOARD_UID_OFFSET * 1)),
|
||||
*((unsigned int *) (OMV_BOARD_UID_ADDR + OMV_BOARD_UID_OFFSET * 0)));
|
||||
#endif
|
||||
return mp_obj_new_str(str, strlen(str));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_0(py_omv_board_id_obj, py_omv_board_id);
|
||||
|
||||
@ -174,11 +174,6 @@ soft_reset:
|
||||
pyexec_frozen_module("_boot.py", false);
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ENABLE_OSPI
|
||||
// Mark the filesystem as an OpenMV storage.
|
||||
file_ll_touch(".openmv_disk");
|
||||
#endif
|
||||
|
||||
// Initialize TinyUSB after the filesystem is mounted.
|
||||
#if MICROPY_HW_ENABLE_USBDEV
|
||||
if (!tusb_inited()) {
|
||||
|
||||
118
ports/qemu/main.c
Normal file
118
ports/qemu/main.c
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Any redistribution, use, or modification in source or binary form
|
||||
* is done solely for personal benefit and not for any commercial
|
||||
* purpose or for monetary gain. For commercial licensing options,
|
||||
* please contact openmv@openmv.io
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "shared/readline/readline.h"
|
||||
#include "shared/runtime/gchelper.h"
|
||||
#include "shared/runtime/pyexec.h"
|
||||
|
||||
#include "omv_boardconfig.h"
|
||||
#include "mp_utils.h"
|
||||
#include "file_utils.h"
|
||||
#include "fb_alloc.h"
|
||||
#include "framebuffer.h"
|
||||
#include "omv_csi.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bool first_soft_reset = true;
|
||||
|
||||
soft_reset:
|
||||
// Initialise stack extents and GC heap.
|
||||
extern uint8_t _estack, _sstack, _heap_start, _heap_end;
|
||||
mp_init_gc_stack(&_sstack, &_estack, &_heap_start, &_heap_end, 1024);
|
||||
|
||||
mp_init();
|
||||
|
||||
fb_alloc_init0();
|
||||
framebuffer_init0();
|
||||
|
||||
#ifdef IMLIB_ENABLE_IMAGE_FILE_IO
|
||||
file_buffer_init0();
|
||||
#endif
|
||||
|
||||
imlib_init_all();
|
||||
|
||||
#if MICROPY_PY_CSI
|
||||
omv_csi_init0();
|
||||
|
||||
if (first_soft_reset) {
|
||||
omv_csi_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
if (pyexec_raw_repl() != 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (pyexec_friendly_repl() != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_printf(&mp_plat_print, "MPY: soft reboot\n");
|
||||
gc_sweep_all();
|
||||
mp_deinit();
|
||||
first_soft_reset = false;
|
||||
goto soft_reset;
|
||||
}
|
||||
|
||||
void gc_collect(void) {
|
||||
gc_collect_start();
|
||||
gc_helper_collect_regs_and_stack();
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
mp_printf(&mp_plat_print, "FATAL: uncaught exception %p\n", val);
|
||||
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(val));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void __fatal_error(const char *msg) {
|
||||
mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14);
|
||||
mp_hal_stdout_tx_strn(msg, strlen(msg));
|
||||
for (;;) {
|
||||
*(volatile uint32_t *) 0x4900C000 ^= 9;
|
||||
for (volatile uint delay = 0; delay < 10000000; delay++) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usbdbg_set_irq_enabled(bool enabled) {
|
||||
|
||||
}
|
||||
85
ports/qemu/omv_csi.c
Normal file
85
ports/qemu/omv_csi.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 OpenMV, LLC.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Any redistribution, use, or modification in source or binary form
|
||||
* is done solely for personal benefit and not for any commercial
|
||||
* purpose or for monetary gain. For commercial licensing options,
|
||||
* please contact openmv@openmv.io
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* QEMU dummy CSI driver.
|
||||
*/
|
||||
#if MICROPY_PY_CSI
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "omv_boardconfig.h"
|
||||
#include "omv_i2c.h"
|
||||
#include "omv_csi.h"
|
||||
|
||||
static int qemu_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||
// Dummy implementation - accept all configurations
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemu_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||
// Dummy implementation
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t qemu_clk_get_frequency(omv_clk_t *clk) {
|
||||
// Dummy implementation - return nominal frequency
|
||||
return clk->freq;
|
||||
}
|
||||
|
||||
static int qemu_clk_set_frequency(omv_clk_t *clk, uint32_t frequency) {
|
||||
// Dummy implementation - accept any frequency
|
||||
clk->freq = frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemu_csi_snapshot(omv_csi_t *csi, image_t *dst_image, uint32_t flags) {
|
||||
// Dummy implementation - return timeout error since there's no camera
|
||||
return OMV_CSI_ERROR_CAPTURE_TIMEOUT;
|
||||
}
|
||||
|
||||
int omv_csi_ops_init(omv_csi_t *csi) {
|
||||
// Set CSI ops to dummy implementations
|
||||
csi->abort = qemu_csi_abort;
|
||||
csi->config = qemu_csi_config;
|
||||
csi->snapshot = qemu_csi_snapshot;
|
||||
|
||||
// Set CSI clock ops
|
||||
csi->clk->freq = OMV_CSI_CLK_FREQUENCY;
|
||||
csi->clk->set_freq = qemu_clk_set_frequency;
|
||||
csi->clk->get_freq = qemu_clk_get_frequency;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // MICROPY_PY_CSI
|
||||
68
ports/qemu/omv_i2c.c
Normal file
68
ports/qemu/omv_i2c.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 OpenMV, LLC.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Any redistribution, use, or modification in source or binary form
|
||||
* is done solely for personal benefit and not for any commercial
|
||||
* purpose or for monetary gain. For commercial licensing options,
|
||||
* please contact openmv@openmv.io
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* QEMU dummy I2C driver.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "omv_portconfig.h"
|
||||
#include "omv_i2c.h"
|
||||
|
||||
int omv_i2c_init(omv_i2c_t *i2c, uint32_t bus_id, uint32_t speed) {
|
||||
i2c->id = bus_id;
|
||||
i2c->speed = speed;
|
||||
i2c->initialized = true;
|
||||
i2c->scl_pin = NULL;
|
||||
i2c->sda_pin = NULL;
|
||||
i2c->inst = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omv_i2c_deinit(omv_i2c_t *i2c) {
|
||||
if (i2c->initialized) {
|
||||
i2c->initialized = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omv_i2c_scan(omv_i2c_t *i2c, uint8_t *list, uint8_t size) {
|
||||
// Dummy implementation - no devices found
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omv_i2c_enable(omv_i2c_t *i2c, bool enable) {
|
||||
// Dummy implementation
|
||||
return 0;
|
||||
}
|
||||
50
ports/qemu/omv_mpconfigport.h
Normal file
50
ports/qemu/omv_mpconfigport.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Any redistribution, use, or modification in source or binary form
|
||||
* is done solely for personal benefit and not for any commercial
|
||||
* purpose or for monetary gain. For commercial licensing options,
|
||||
* please contact openmv@openmv.io
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* MicroPython port configuration.
|
||||
*/
|
||||
#define MICROPY_NLR_RAISE_HOOK \
|
||||
do { \
|
||||
extern void fb_alloc_free_till_mark(); \
|
||||
fb_alloc_free_till_mark(); \
|
||||
} while (0);
|
||||
|
||||
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
|
||||
typedef int mp_int_t; // must be pointer size
|
||||
typedef unsigned int mp_uint_t; // must be pointer size
|
||||
|
||||
#define MICROPY_PY_TIME (1)
|
||||
#define MICROPY_GC_SPLIT_HEAP (1)
|
||||
#define MICROPY_BANNER_NAME_AND_VERSION "OpenMV " OPENMV_GIT_TAG "; MicroPython " MICROPY_GIT_TAG
|
||||
|
||||
#include <mpconfigport.h>
|
||||
|
||||
#undef MICROPY_MEM_STATS
|
||||
#undef MICROPY_MALLOC_USES_ALLOCATED_SIZE
|
||||
59
ports/qemu/omv_portconfig.h
Normal file
59
ports/qemu/omv_portconfig.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 OpenMV, LLC.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Any redistribution, use, or modification in source or binary form
|
||||
* is done solely for personal benefit and not for any commercial
|
||||
* purpose or for monetary gain. For commercial licensing options,
|
||||
* please contact openmv@openmv.io
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* OpenMV QEMU port abstraction layer.
|
||||
*/
|
||||
#ifndef __OMV_PORTCONFIG_H__
|
||||
#define __OMV_PORTCONFIG_H__
|
||||
#include <stdlib.h>
|
||||
|
||||
// omv_gpio_t definitions
|
||||
typedef void *omv_gpio_t;
|
||||
|
||||
// GPIO modes, speeds, and pull configurations (dummy values for QEMU)
|
||||
#define OMV_GPIO_MODE_INPUT (0)
|
||||
#define OMV_GPIO_MODE_OUTPUT (1)
|
||||
#define OMV_GPIO_MODE_OUTPUT_OD (2)
|
||||
#define OMV_GPIO_MODE_ALT (3)
|
||||
#define OMV_GPIO_MODE_ALT_OD (4)
|
||||
|
||||
#define OMV_GPIO_PULL_NONE (0)
|
||||
#define OMV_GPIO_PULL_UP (1)
|
||||
#define OMV_GPIO_PULL_DOWN (2)
|
||||
|
||||
#define OMV_GPIO_SPEED_LOW (0)
|
||||
#define OMV_GPIO_SPEED_MED (1)
|
||||
#define OMV_GPIO_SPEED_HIGH (2)
|
||||
#define OMV_GPIO_SPEED_MAX (3)
|
||||
|
||||
// omv_i2c_t definitions
|
||||
typedef void *omv_i2c_dev_t;
|
||||
|
||||
#endif // __OMV_PORTCONFIG_H__
|
||||
170
ports/qemu/omv_portconfig.mk
Normal file
170
ports/qemu/omv_portconfig.mk
Normal file
@ -0,0 +1,170 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright (C) 2025 OpenMV, LLC.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# Set startup and system files for CMSIS Makefile.
|
||||
LDSCRIPT ?= qemu
|
||||
ROMFS_IMAGE := $(FW_DIR)/romfs.stamp
|
||||
ROMFS_CONFIG := $(OMV_BOARD_CONFIG_DIR)/romfs.json
|
||||
|
||||
# Compiler Flags
|
||||
CFLAGS += -std=gnu11 \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-Warray-bounds \
|
||||
-nostartfiles \
|
||||
-fdata-sections \
|
||||
-ffunction-sections \
|
||||
-fno-inline-small-functions \
|
||||
-mthumb \
|
||||
-mcpu=$(CPU) \
|
||||
-mfpu=$(FPU) \
|
||||
-mfloat-abi=hard
|
||||
|
||||
CFLAGS += -D$(TARGET) \
|
||||
-DQEMU_BUILD \
|
||||
-D__FPU_PRESENT=1 \
|
||||
-D__FPU_USED=1 \
|
||||
-D__VFP_FP__ \
|
||||
-DARM_NN_TRUNCATE=1 \
|
||||
-DCMSIS_MCU_H='<string.h>' \
|
||||
$(OMV_BOARD_CFLAGS)
|
||||
|
||||
# Linker Flags
|
||||
LDFLAGS = -mthumb \
|
||||
-nostartfiles \
|
||||
-mcpu=$(CPU) \
|
||||
-mfpu=$(FPU) \
|
||||
-mfloat-abi=hard \
|
||||
-mabi=aapcs-linux \
|
||||
-Wl,--print-memory-usage \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,-T$(BUILD)/$(LDSCRIPT).lds \
|
||||
-Wl,-Map=$(BUILD)/$(FIRMWARE).map
|
||||
|
||||
OMV_CFLAGS += -I$(TOP_DIR)
|
||||
OMV_CFLAGS += -I$(TOP_DIR)/$(COMMON_DIR)
|
||||
OMV_CFLAGS += -I$(TOP_DIR)/modules
|
||||
OMV_CFLAGS += -I$(TOP_DIR)/ports/$(PORT)
|
||||
OMV_CFLAGS += -I$(TOP_DIR)/ports/$(PORT)/modules
|
||||
OMV_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR)
|
||||
|
||||
MPY_CFLAGS += -I$(MP_BOARD_CONFIG_DIR)
|
||||
MPY_CFLAGS += -I$(BUILD)/$(MICROPY_DIR)
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/py
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/oofatfs
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/tinyusb/src
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/lwip/src/include
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/shared/tinyusb
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/qemu
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/qemu/lwip_inc
|
||||
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/shared/runtime
|
||||
|
||||
MPY_CFLAGS += -DMICROPY_PY_LWIP=$(MICROPY_PY_LWIP)
|
||||
MPY_CFLAGS += -DMICROPY_PY_SSL=$(MICROPY_PY_SSL)
|
||||
MPY_CFLAGS += -DMICROPY_PY_SSL_ECDSA_SIGN_ALT=$(MICROPY_PY_SSL_ECDSA_SIGN_ALT)
|
||||
MPY_CFLAGS += -DMICROPY_SSL_MBEDTLS=$(MICROPY_SSL_MBEDTLS)
|
||||
MPY_CFLAGS += -DMICROPY_PY_NETWORK_CYW43=$(MICROPY_PY_NETWORK_CYW43)
|
||||
MPY_CFLAGS += -DMICROPY_PY_BLUETOOTH=$(MICROPY_PY_BLUETOOTH)
|
||||
MPY_CFLAGS += -DMICROPY_BLUETOOTH_NIMBLE=$(MICROPY_BLUETOOTH_NIMBLE)
|
||||
MPY_CFLAGS += -DMICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
|
||||
MPY_CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT
|
||||
|
||||
MPY_MKARGS += CMSIS_DIR=$(TOP_DIR)/$(CMSIS_DIR)
|
||||
MPY_MKARGS += MICROPY_VFS_LFS2=0
|
||||
MPY_MKARGS += CFLAGS_EXTRA="-std=gnu11"
|
||||
MPY_MKARGS += MICROPY_PY_LWIP=$(MICROPY_PY_LWIP)
|
||||
MPY_MKARGS += MICROPY_PY_SSL=$(MICROPY_PY_SSL)
|
||||
MPY_MKARGS += MICROPY_PY_SSL_ECDSA_SIGN_ALT=$(MICROPY_PY_SSL_ECDSA_SIGN_ALT)
|
||||
MPY_MKARGS += MICROPY_SSL_MBEDTLS=$(MICROPY_SSL_MBEDTLS)
|
||||
MPY_MKARGS += MICROPY_PY_NETWORK_CYW43=$(MICROPY_PY_NETWORK_CYW43)
|
||||
MPY_MKARGS += MICROPY_PY_BLUETOOTH=$(MICROPY_PY_BLUETOOTH)
|
||||
MPY_MKARGS += MICROPY_BLUETOOTH_NIMBLE=$(MICROPY_BLUETOOTH_NIMBLE)
|
||||
MPY_MKARGS += MICROPY_FLOAT_IMPL=float
|
||||
MPY_MKARGS += SUPPORTS_HARDWARE_FP_SINGLE=1
|
||||
|
||||
CFLAGS += $(HAL_CFLAGS) $(MPY_CFLAGS) $(OMV_CFLAGS)
|
||||
|
||||
# Firmware objects from .mk files.
|
||||
include lib/cmsis/cmsis.mk
|
||||
include common/common.mk
|
||||
include drivers/drivers.mk
|
||||
include lib/imlib/imlib.mk
|
||||
include lib/tflm/tflm.mk
|
||||
include ports/ports.mk
|
||||
include common/micropy.mk
|
||||
|
||||
# Firmware objects from port.
|
||||
MPY_FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
||||
uart.o \
|
||||
mphalport.o \
|
||||
frozen_content.o \
|
||||
mcu/arm/errorhandler.o \
|
||||
mcu/arm/startup.o \
|
||||
mcu/arm/systick.o \
|
||||
)
|
||||
|
||||
ifeq ($(MICROPY_PY_ML_TFLM), 1)
|
||||
ifeq ($(CPU),cortex-m55)
|
||||
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/libtflm/lib/libtflm-cortex-m55-release.a
|
||||
else
|
||||
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/libtflm/lib/libtflm-$(CPU)+fp-release.a
|
||||
endif
|
||||
endif
|
||||
|
||||
###################################################
|
||||
all: $(ROMFS_IMAGE)
|
||||
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
|
||||
|
||||
# This target builds MicroPython.
|
||||
MICROPYTHON: | FIRM_DIRS
|
||||
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MPY_MKARGS)
|
||||
|
||||
$(OMV_FIRM_OBJ): | MICROPYTHON
|
||||
|
||||
# This target builds the firmware.
|
||||
$(FIRMWARE): $(OMV_FIRM_OBJ)
|
||||
$(CPP) -P -E -DLINKER_SCRIPT -I$(COMMON_DIR) -I$(OMV_BOARD_CONFIG_DIR) \
|
||||
ports/$(PORT)/$(LDSCRIPT).ld.S > $(BUILD)/$(LDSCRIPT).lds
|
||||
$(CC) $(LDFLAGS) $(OMV_FIRM_OBJ) $(MPY_FIRM_OBJ) -o $(FW_DIR)/$(FIRMWARE).elf $(LIBS) -lm
|
||||
$(OBJCOPY) -Obinary $(FW_DIR)/$(FIRMWARE).elf $(FW_DIR)/$(FIRMWARE).bin
|
||||
|
||||
$(ROMFS_IMAGE): $(ROMFS_CONFIG) | $(FIRMWARE)
|
||||
$(ECHO) "GEN romfs image"
|
||||
$(PYTHON) $(TOOLS_DIR)/$(MKROMFS) \
|
||||
--top-dir $(TOP_DIR) \
|
||||
--out-dir $(FW_DIR) \
|
||||
--build-dir $(BUILD)/lib/models \
|
||||
$(STEDGE_ARGS) --config $(ROMFS_CONFIG)
|
||||
touch $@
|
||||
|
||||
QEMU_SYSTEM = qemu-system-arm
|
||||
QEMU_ARGS += -machine $(QEMU_MACHINE) -nographic -monitor null -semihosting
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
QEMU_ARGS += -s -S
|
||||
endif
|
||||
|
||||
run: $(ROMFS_IMAGE)
|
||||
$(QEMU_SYSTEM) $(QEMU_ARGS) -serial pty -kernel $(FW_DIR)/$(FIRMWARE).elf
|
||||
|
||||
include common/mkrules.mk
|
||||
73
ports/qemu/qemu.ld.S
Normal file
73
ports/qemu/qemu.ld.S
Normal file
@ -0,0 +1,73 @@
|
||||
/* This file is part of the MicroPython project, http://micropython.org/
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2018 Damien P. George
|
||||
*/
|
||||
|
||||
#include "omv_boardconfig.h"
|
||||
|
||||
MEMORY
|
||||
{
|
||||
#if defined(OMV_ITCM_ORIGIN)
|
||||
ITCM (xrw) : ORIGIN = OMV_ITCM_ORIGIN, LENGTH = OMV_ITCM_LENGTH
|
||||
#endif
|
||||
#if defined(OMV_SRAM1_ORIGIN)
|
||||
SRAM1 (xrw) : ORIGIN = OMV_SRAM1_ORIGIN, LENGTH = OMV_SRAM1_LENGTH
|
||||
#endif
|
||||
#if defined(OMV_SRAM2_ORIGIN)
|
||||
SRAM2 (xrw) : ORIGIN = OMV_SRAM2_ORIGIN, LENGTH = OMV_SRAM2_LENGTH
|
||||
#endif
|
||||
FLASH_ISR (rx) : ORIGIN = OMV_FLASH_ISR_ORIGIN, LENGTH = OMV_FLASH_ISR_LENGTH
|
||||
FLASH_TEXT (rx) : ORIGIN = OMV_FLASH_TXT_ORIGIN, LENGTH = OMV_FLASH_TXT_LENGTH
|
||||
}
|
||||
|
||||
/* Define output sections */
|
||||
SECTIONS
|
||||
{
|
||||
.isr_vector : ALIGN(4)
|
||||
{
|
||||
KEEP(*(.isr_vector))
|
||||
. = ALIGN(4);
|
||||
} >FLASH_ISR
|
||||
|
||||
/* The program code and other data goes into FLASH */
|
||||
.text : ALIGN(4)
|
||||
{
|
||||
*(.text*) // .text* sections (code)
|
||||
. = ALIGN(4);
|
||||
*(.rodata*) // .rodata* sections (constants, strings, etc.)
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
} >FLASH_TEXT
|
||||
|
||||
/* The address used as the source for copying the initialized data section. */
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
/* Initialized data sections */
|
||||
.data : ALIGN(4)
|
||||
{
|
||||
_sdata = .; // Used by the startup to initialize the data section
|
||||
*(.data) // .data sections
|
||||
. = ALIGN(4);
|
||||
*(.data*) // .data* sections
|
||||
. = ALIGN(4);
|
||||
_edata = .; // Define a global symbol at data end
|
||||
} >OMV_MAIN_MEMORY AT> FLASH_TEXT
|
||||
|
||||
/* Uninitialized data section */
|
||||
.bss (NOLOAD) : ALIGN(4)
|
||||
{
|
||||
_sbss = .; // Used by the startup to initialize the .bss section
|
||||
__bss_start__ = .;
|
||||
. = ALIGN(4);
|
||||
*(.bss*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .; // Define a global symbol at bss end
|
||||
__bss_end__ = .;
|
||||
} >OMV_MAIN_MEMORY
|
||||
|
||||
#include "common.ld.S"
|
||||
}
|
||||
@ -63,28 +63,22 @@ int hash_digest(uint8_t *buffer, uint32_t size, uint8_t *digest) {
|
||||
}
|
||||
|
||||
int hash_from_file(const char *path, uint8_t *digest) {
|
||||
FIL fp;
|
||||
file_t fp;
|
||||
uint32_t offset = 0;
|
||||
UINT bytes = 0;
|
||||
UINT bytes_out = 0;
|
||||
size_t bytes = 0;
|
||||
|
||||
int ret = -1;
|
||||
uint8_t *buf = fb_alloc(BLOCK_SIZE, FB_ALLOC_NO_HINT);
|
||||
|
||||
if (file_ll_open(&fp, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||
|
||||
// File size
|
||||
uint32_t size = f_size(&fp);
|
||||
uint32_t size = file_size(&fp);
|
||||
|
||||
while (size) {
|
||||
// Read a block.
|
||||
bytes = MIN(size, BLOCK_SIZE);
|
||||
if (file_ll_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) {
|
||||
printf("hash_from_file: file read error!\n");
|
||||
goto error;
|
||||
}
|
||||
file_read(&fp, buf, bytes);
|
||||
|
||||
// Accumulate buffer.
|
||||
if ((size - bytes) > 0) {
|
||||
@ -107,7 +101,7 @@ int hash_from_file(const char *path, uint8_t *digest) {
|
||||
|
||||
error:
|
||||
fb_free();
|
||||
file_ll_close(&fp);
|
||||
file_close(&fp);
|
||||
return ret;
|
||||
}
|
||||
#endif //OMV_ENABLE_HASH == 1
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "py/objlist.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/builtin.h"
|
||||
#include "shared/netutils/netutils.h"
|
||||
#include "extmod/modnetwork.h"
|
||||
#include "pin.h"
|
||||
@ -342,13 +343,15 @@ static mp_obj_t py_winc_fw_dump(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
}
|
||||
|
||||
static mp_obj_t py_winc_fw_update(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
FRESULT res;
|
||||
FILINFO fno;
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
if ((res = file_ll_stat(path, &fno)) != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) file_strerror(res));
|
||||
}
|
||||
// Check if file exists by attempting to open it
|
||||
mp_obj_t args[2] = {
|
||||
path_in,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_rb)
|
||||
};
|
||||
mp_obj_t file = mp_builtin_open(2, args, (mp_map_t *) &mp_const_empty_map);
|
||||
mp_stream_close(file);
|
||||
|
||||
// Erase the WINC1500 flash.
|
||||
printf("Erasing flash...\n");
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# This example shows off Google's MediaPipe Palm Detection model.
|
||||
#
|
||||
# NOTE: This exaxmple requires an OpenMV Cam with an NPU like the AE3 or N6 to run real-time.
|
||||
|
||||
import csi
|
||||
import time
|
||||
import ml
|
||||
from ml.postprocessing.mediapipe import BlazePalm
|
||||
|
||||
# Initialize the sensor.
|
||||
csi0 = csi.CSI()
|
||||
csi0.reset()
|
||||
csi0.pixformat(csi.RGB565)
|
||||
csi0.framesize(csi.VGA)
|
||||
csi0.window((400, 400))
|
||||
|
||||
# Load built-in palm detection model
|
||||
model = ml.Model("/rom/palm_detection_full_192.tflite", postprocess=BlazePalm(threshold=0.4))
|
||||
print(model)
|
||||
|
||||
# Line connections between hand joints for drawing the hand skeleton.
|
||||
palm_lines = ((0, 1), (1, 2), (2, 3), (3, 4), (4, 0), (0, 5), (5, 6))
|
||||
|
||||
# Visualization parameters.
|
||||
palm_labels = ["palm"]
|
||||
palm_colors = [(0, 0, 255)]
|
||||
kp_color = (255, 0, 0)
|
||||
line_color = (0, 255, 0)
|
||||
|
||||
clock = time.clock()
|
||||
while True:
|
||||
clock.tick()
|
||||
img = csi0.snapshot()
|
||||
|
||||
# palms is a list of ((x, y, w, h), score, keypoints) tuples
|
||||
palms = model.predict([img])
|
||||
|
||||
# Draw bounding boxes around the detected palms and keypoints.
|
||||
if palms:
|
||||
for r, score, keypoints in palms[0]:
|
||||
ml.utils.draw_predictions(img, [r], palm_labels, palm_colors, format=None)
|
||||
|
||||
# keypoints is a ndarray of shape (7, 2)
|
||||
# 0 - wrist (x, y)
|
||||
# 1 - index finger mcp (x, y)
|
||||
# 2 - middle finger mcp (x, y)
|
||||
# 3 - ring finger mcp (x, y)
|
||||
# 4 - pinky mcp (x, y)
|
||||
# 5 - thumb cmc (x, y)
|
||||
# 6 - thumb mcp (x, y)
|
||||
#
|
||||
# mcp = Metacarpophalangeal Joint - the knuckle
|
||||
# cmc = Carpometacarpal Joint - the base of the thumb
|
||||
ml.utils.draw_skeleton(img, keypoints, palm_lines, kp_color=kp_color, line_color=line_color)
|
||||
|
||||
print(clock.fps(), "fps")
|
||||
@ -0,0 +1,77 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# This example shows off Google's MediaPipe Hand Landmarks Detection model for multiple hands.
|
||||
#
|
||||
# NOTE: This exaxmple requires an OpenMV Cam with an NPU like the AE3 or N6 to run real-time.
|
||||
|
||||
import csi
|
||||
import time
|
||||
import ml
|
||||
from ml.preprocessing import Normalization
|
||||
from ml.postprocessing.mediapipe import BlazePalm
|
||||
from ml.postprocessing.mediapipe import HandLandmarks
|
||||
|
||||
# Initialize the sensor.
|
||||
csi0 = csi.CSI()
|
||||
csi0.reset()
|
||||
csi0.pixformat(csi.RGB565)
|
||||
csi0.framesize(csi.VGA)
|
||||
csi0.window((400, 400))
|
||||
|
||||
# Load built-in palm detection model
|
||||
palm_detection = ml.Model("/rom/palm_detection_full_192.tflite", postprocess=BlazePalm(threshold=0.4))
|
||||
print(palm_detection)
|
||||
|
||||
# Load built-in hand landmark model
|
||||
hand_landmarks = ml.Model("/rom/hand_landmarks_full_224.tflite", postprocess=HandLandmarks(threshold=0.4))
|
||||
print(hand_landmarks)
|
||||
|
||||
# Line connections between hand joints for drawing the hand skeleton.
|
||||
hand_lines = ((0, 1), (1, 2), (2, 3), (3, 4), (0, 5), (5, 6), (6, 7), (7, 8),
|
||||
(5, 9), (9, 10), (10, 11), (11, 12), (9, 13), (13, 14), (14, 15), (15, 16),
|
||||
(13, 17), (17, 18), (18, 19), (19, 20), (0, 17))
|
||||
|
||||
# Visualization parameters.
|
||||
palm_colors = [(0, 0, 255)]
|
||||
kp_color = (255, 0, 0)
|
||||
line_color = (0, 255, 0)
|
||||
|
||||
clock = time.clock()
|
||||
while True:
|
||||
clock.tick()
|
||||
img = csi0.snapshot()
|
||||
|
||||
# palms is a list of ((x, y, w, h), score, keypoints) tuples
|
||||
palms = palm_detection.predict([img])
|
||||
|
||||
if palms:
|
||||
for r, score, keypoints in palms[0]:
|
||||
# rect is (x, y, w, h) - enlarge by 3x for hand landmarks model
|
||||
wider_rect = (r[0] - r[2], r[1] - r[3], r[2] * 3, r[3] * 3)
|
||||
# Operate on just the ROI of the detected palm
|
||||
n = Normalization(roi=wider_rect)
|
||||
|
||||
# hands is a list of ((x, y, w, h), score, keypoints) tuples
|
||||
# index 0 (if present) is left hand
|
||||
# index 1 (if present) is right hand
|
||||
hands = hand_landmarks.predict([n(img)])
|
||||
|
||||
# Draw bounding boxes around the detected hands and keypoints.
|
||||
for i, detections in enumerate(hands):
|
||||
for r, score, keypoints in detections:
|
||||
ml.utils.draw_predictions(img, [r], ["right" if i else "left"], palm_colors, format=None)
|
||||
|
||||
# keypoints: ndarray (21, 3) of hand joints (x, y, z)
|
||||
# Indices follow MediaPipe convention:
|
||||
# 0: wrist
|
||||
# Thumb: 1 cmc, 2 mcp, 3 ip, 4 tip
|
||||
# Index: 5 mcp, 6 pip, 7 dip, 8 tip
|
||||
# Middle: 9 mcp, 10 pip, 11 dip, 12 tip
|
||||
# Ring: 13 mcp, 14 pip, 15 dip, 16 tip
|
||||
# Pinky: 17 mcp, 18 pip, 19 dip, 20 tip
|
||||
# (cmc=base, mcp=knuckle, pip=mid, dip=distal, ip=thumb joint, tip=fingertip)
|
||||
ml.utils.draw_skeleton(img, keypoints, hand_lines, kp_color=kp_color, line_color=line_color)
|
||||
|
||||
print(clock.fps(), "fps")
|
||||
@ -0,0 +1,95 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# This example shows off Google's MediaPipe Hand Landmarks Detection model for a single hand.
|
||||
#
|
||||
# NOTE: This exaxmple requires an OpenMV Cam with an NPU like the AE3 or N6 to run real-time.
|
||||
|
||||
import csi
|
||||
import time
|
||||
import ml
|
||||
from ml.preprocessing import Normalization
|
||||
from ml.postprocessing.mediapipe import BlazePalm
|
||||
from ml.postprocessing.mediapipe import HandLandmarks
|
||||
|
||||
# Initialize the sensor.
|
||||
csi0 = csi.CSI()
|
||||
csi0.reset()
|
||||
csi0.pixformat(csi.RGB565)
|
||||
csi0.framesize(csi.VGA)
|
||||
csi0.window((400, 400))
|
||||
|
||||
# Load built-in palm detection model
|
||||
palm_detection = ml.Model("/rom/palm_detection_full_192.tflite", postprocess=BlazePalm(threshold=0.4))
|
||||
print(palm_detection)
|
||||
|
||||
# Load built-in hand landmark model
|
||||
hand_landmarks = ml.Model("/rom/hand_landmarks_full_224.tflite", postprocess=HandLandmarks(threshold=0.4))
|
||||
print(hand_landmarks)
|
||||
|
||||
# Line connections between hand joints for drawing the hand skeleton.
|
||||
hand_lines = ((0, 1), (1, 2), (2, 3), (3, 4), (0, 5), (5, 6), (6, 7), (7, 8),
|
||||
(5, 9), (9, 10), (10, 11), (11, 12), (9, 13), (13, 14), (14, 15), (15, 16),
|
||||
(13, 17), (17, 18), (18, 19), (19, 20), (0, 17))
|
||||
|
||||
# Visualization parameters.
|
||||
palm_colors = [(0, 0, 255)]
|
||||
kp_color = (255, 0, 0)
|
||||
line_color = (0, 255, 0)
|
||||
|
||||
# Tracking vars.
|
||||
n = None
|
||||
|
||||
clock = time.clock()
|
||||
while True:
|
||||
clock.tick()
|
||||
img = csi0.snapshot()
|
||||
|
||||
if n is None:
|
||||
# palms is a list of ((x, y, w, h), score, keypoints) tuples
|
||||
palms = palm_detection.predict([img])
|
||||
|
||||
if palms:
|
||||
for r, score, keypoints in palms[0]:
|
||||
# rect is (x, y, w, h) - enlarge by 3x for hand landmarks model
|
||||
wider_rect = (r[0] - r[2], r[1] - r[3], r[2] * 3, r[3] * 3)
|
||||
# Operate on just the ROI of the detected palm
|
||||
n = Normalization(roi=wider_rect)
|
||||
|
||||
else:
|
||||
# hands is a list of ((x, y, w, h), score, keypoints) tuples
|
||||
# index 0 (if present) is left hand
|
||||
# index 1 (if present) is right hand
|
||||
hands = hand_landmarks.predict([n(img)])
|
||||
|
||||
# No hands detected, reset the tracker.
|
||||
if not hands:
|
||||
n = None
|
||||
continue
|
||||
|
||||
# Draw bounding boxes around the detected hands and keypoints.
|
||||
for i, detections in enumerate(hands):
|
||||
for r, score, keypoints in detections:
|
||||
ml.utils.draw_predictions(img, [r], ["right" if i else "left"], [(0, 0, 255)], format=None)
|
||||
|
||||
# keypoints: ndarray (21, 3) of hand joints (x, y, z)
|
||||
# Indices follow MediaPipe convention:
|
||||
# 0: wrist
|
||||
# Thumb: 1 cmc, 2 mcp, 3 ip, 4 tip
|
||||
# Index: 5 mcp, 6 pip, 7 dip, 8 tip
|
||||
# Middle: 9 mcp, 10 pip, 11 dip, 12 tip
|
||||
# Ring: 13 mcp, 14 pip, 15 dip, 16 tip
|
||||
# Pinky: 17 mcp, 18 pip, 19 dip, 20 tip
|
||||
# (cmc=base, mcp=knuckle, pip=mid, dip=distal, ip=thumb joint, tip=fingertip)
|
||||
ml.utils.draw_skeleton(img, keypoints, hand_lines, kp_color=kp_color, line_color=line_color)
|
||||
|
||||
# Center new_wider_rect on hand for tracking
|
||||
new_wider_rect = (r[0] + (r[2] // 2) - (wider_rect[2] // 2),
|
||||
r[1] + (r[3] // 2) - (wider_rect[3] // 2),
|
||||
wider_rect[2],
|
||||
wider_rect[3])
|
||||
# Operate on just the ROI of the detected hand
|
||||
n = Normalization(roi=new_wider_rect)
|
||||
|
||||
print(clock.fps(), "fps")
|
||||
@ -0,0 +1,44 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# TensorFlow Lite YOLO LC Person Detector Example
|
||||
#
|
||||
# YOLO LC is a variant of YOLOV2 that is fast enough to run on OpenMV Cams without NPUs.
|
||||
|
||||
import csi
|
||||
import time
|
||||
import ml
|
||||
from ml.postprocessing.darknet import YoloLC
|
||||
|
||||
# Initialize the sensor.
|
||||
csi0 = csi.CSI()
|
||||
csi0.reset()
|
||||
csi0.pixformat(csi.RGB565)
|
||||
csi0.framesize(csi.VGA)
|
||||
csi0.window((400, 400))
|
||||
|
||||
# Load built-in person detection model
|
||||
model = ml.Model("/rom/yolo_lc_192.tflite", postprocess=YoloLC(threshold=0.4))
|
||||
print(model)
|
||||
|
||||
# Visualization parameters.
|
||||
n = len(model.labels)
|
||||
model_class_colors = [(int(255 * i // n), int(255 * (n - i - 1) // n), 255) for i in range(n)]
|
||||
|
||||
clock = time.clock()
|
||||
while True:
|
||||
clock.tick()
|
||||
img = csi0.snapshot()
|
||||
|
||||
# boxes is a list of list per class of ((x, y, w, h), score) tuples
|
||||
boxes = model.predict([img])
|
||||
|
||||
# Draw bounding boxes around the detected objects
|
||||
for i, class_detections in enumerate(boxes):
|
||||
rects = [r for r, score in class_detections]
|
||||
labels = [model.labels[i] for j in range(len(rects))]
|
||||
colors = [model_class_colors[i] for j in range(len(rects))]
|
||||
ml.utils.draw_predictions(img, rects, labels, colors, format=None)
|
||||
|
||||
print(clock.fps(), "fps")
|
||||
@ -0,0 +1,46 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# TensorFlow Lite YOLO V8 Example
|
||||
#
|
||||
# This example runs a YOLO V8 person detection model.
|
||||
#
|
||||
# NOTE: This exaxmple requires an OpenMV Cam with an NPU like the AE3 or N6 to run real-time.
|
||||
|
||||
import csi
|
||||
import time
|
||||
import ml
|
||||
from ml.postprocessing.ultralytics import YoloV8
|
||||
|
||||
# Initialize the sensor.
|
||||
csi0 = csi.CSI()
|
||||
csi0.reset()
|
||||
csi0.pixformat(csi.RGB565)
|
||||
csi0.framesize(csi.VGA)
|
||||
csi0.window((400, 400))
|
||||
|
||||
# Load YOLO V8 model from ROM FS.
|
||||
model = ml.Model("/rom/yolov8n_192.tflite", postprocess=YoloV8(threshold=0.4))
|
||||
print(model)
|
||||
|
||||
# Visualization parameters.
|
||||
n = len(model.labels)
|
||||
model_class_colors = [(int(255 * i // n), int(255 * (n - i - 1) // n), 255) for i in range(n)]
|
||||
|
||||
clock = time.clock()
|
||||
while True:
|
||||
clock.tick()
|
||||
img = csi0.snapshot()
|
||||
|
||||
# boxes is a list of list per class of ((x, y, w, h), score) tuples
|
||||
boxes = model.predict([img])
|
||||
|
||||
# Draw bounding boxes around the detected objects
|
||||
for i, class_detections in enumerate(boxes):
|
||||
rects = [r for r, score in class_detections]
|
||||
labels = [model.labels[i] for j in range(len(rects))]
|
||||
colors = [model_class_colors[i] for j in range(len(rects))]
|
||||
ml.utils.draw_predictions(img, rects, labels, colors, format=None)
|
||||
|
||||
print(clock.fps(), "fps")
|
||||
@ -1,63 +0,0 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2023 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# Colorbar Test Example
|
||||
#
|
||||
# This example is the color bar test run by each OpenMV Cam before being allowed
|
||||
# out of the factory. The OMV sensors can output a color bar image which you
|
||||
# can threshold to check the the camera bus is connected correctly.
|
||||
|
||||
import sensor
|
||||
|
||||
sensor.reset()
|
||||
# Set sensor settings
|
||||
sensor.set_brightness(0)
|
||||
sensor.set_saturation(3)
|
||||
sensor.set_gainceiling(8)
|
||||
sensor.set_contrast(2)
|
||||
|
||||
# Set sensor pixel format
|
||||
sensor.set_framesize(sensor.QVGA)
|
||||
sensor.set_pixformat(sensor.RGB565)
|
||||
|
||||
# Enable colorbar test mode
|
||||
sensor.set_colorbar(True)
|
||||
|
||||
# Skip a few frames to allow the sensor settle down
|
||||
for i in range(0, 30):
|
||||
image = sensor.snapshot()
|
||||
|
||||
# Color bars thresholds
|
||||
t = [
|
||||
lambda r, g, b: r < 70 and g < 70 and b < 70, # Black
|
||||
lambda r, g, b: r < 70 and g < 70 and b > 200, # Blue
|
||||
lambda r, g, b: r > 200 and g < 70 and b < 70, # Red
|
||||
lambda r, g, b: r > 200 and g < 70 and b > 200, # Purple
|
||||
lambda r, g, b: r < 70 and g > 200 and b < 70, # Green
|
||||
lambda r, g, b: r < 70 and g > 200 and b > 200, # Aqua
|
||||
lambda r, g, b: r > 200 and g > 200 and b < 70, # Yellow
|
||||
lambda r, g, b: r > 200 and g > 200 and b > 200,
|
||||
] # White
|
||||
|
||||
# color bars are inverted for OV7725
|
||||
if sensor.get_id() == sensor.OV7725:
|
||||
t = t[::-1]
|
||||
|
||||
# 320x240 image with 8 color bars each one is approx 40 pixels.
|
||||
# we start from the center of the frame buffer, and average the
|
||||
# values of 10 sample pixels from the center of each color bar.
|
||||
for i in range(0, 8):
|
||||
avg = (0, 0, 0)
|
||||
idx = 40 * i + 20 # center of colorbars
|
||||
for off in range(0, 10): # avg 10 pixels
|
||||
rgb = image.get_pixel(idx + off, 120)
|
||||
avg = tuple(map(sum, zip(avg, rgb)))
|
||||
|
||||
if not t[i](avg[0] / 10, avg[1] / 10, avg[2] / 10):
|
||||
raise Exception(
|
||||
"COLOR BARS TEST FAILED. "
|
||||
"BAR#(%d): RGB(%d,%d,%d)" % (i + 1, avg[0] / 10, avg[1] / 10, avg[2] / 10)
|
||||
)
|
||||
|
||||
print("COLOR BARS TEST PASSED...")
|
||||
@ -1,19 +0,0 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2023 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# FPS Test Script.
|
||||
import sensor
|
||||
import time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QQVGA (or others)
|
||||
sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
|
||||
sensor.set_colorbar(True) # Enable colorbars output
|
||||
|
||||
clock = time.clock() # Tracks FPS.
|
||||
for i in range(0, 600):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
sensor.snapshot() # Capture snapshot.
|
||||
|
||||
print("FPS:", clock.fps())
|
||||
@ -1,89 +0,0 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2023 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# Self Test Example
|
||||
#
|
||||
# This example shows how your OpenMV Cam tests itself before being allowed out
|
||||
# of the factory. Every OpenMV Cam should pass this test.
|
||||
|
||||
import sensor
|
||||
import pyb
|
||||
|
||||
|
||||
def test_int_adc():
|
||||
adc = pyb.ADCAll(12)
|
||||
# Test VBAT
|
||||
vbat = adc.read_core_vbat()
|
||||
vbat_diff = abs(vbat - 3.3)
|
||||
if vbat_diff > 0.1:
|
||||
raise Exception("INTERNAL ADC TEST FAILED VBAT=%fv" % vbat)
|
||||
|
||||
# Test VREF
|
||||
vref = adc.read_core_vref()
|
||||
vref_diff = abs(vref - 1.2)
|
||||
if vref_diff > 0.1:
|
||||
raise Exception("INTERNAL ADC TEST FAILED VREF=%fv" % vref)
|
||||
adc = None
|
||||
print("INTERNAL ADC TEST PASSED...")
|
||||
|
||||
|
||||
def test_color_bars():
|
||||
sensor.reset()
|
||||
# Set sensor settings
|
||||
sensor.set_brightness(0)
|
||||
sensor.set_saturation(3)
|
||||
sensor.set_gainceiling(8)
|
||||
sensor.set_contrast(2)
|
||||
|
||||
# Set sensor pixel format
|
||||
sensor.set_framesize(sensor.QVGA)
|
||||
sensor.set_pixformat(sensor.RGB565)
|
||||
|
||||
# Enable colorbar test mode
|
||||
sensor.set_colorbar(True)
|
||||
|
||||
# Skip a few frames to allow the sensor settle down
|
||||
for i in range(0, 100):
|
||||
image = sensor.snapshot()
|
||||
|
||||
# color bars thresholds
|
||||
t = [
|
||||
lambda r, g, b: r < 70 and g < 70 and b < 70, # Black
|
||||
lambda r, g, b: r < 70 and g < 70 and b > 200, # Blue
|
||||
lambda r, g, b: r > 200 and g < 70 and b < 70, # Red
|
||||
lambda r, g, b: r > 200 and g < 70 and b > 200, # Purple
|
||||
lambda r, g, b: r < 70 and g > 200 and b < 70, # Green
|
||||
lambda r, g, b: r < 70 and g > 200 and b > 200, # Aqua
|
||||
lambda r, g, b: r > 200 and g > 200 and b < 70, # Yellow
|
||||
lambda r, g, b: r > 200 and g > 200 and b > 200,
|
||||
] # White
|
||||
|
||||
# color bars are inverted for OV7725
|
||||
if sensor.get_id() == sensor.OV7725:
|
||||
t = t[::-1]
|
||||
|
||||
# 320x240 image with 8 color bars each one is approx 40 pixels.
|
||||
# we start from the center of the frame buffer, and average the
|
||||
# values of 10 sample pixels from the center of each color bar.
|
||||
for i in range(0, 8):
|
||||
avg = (0, 0, 0)
|
||||
idx = 40 * i + 20 # center of colorbars
|
||||
for off in range(0, 10): # avg 10 pixels
|
||||
rgb = image.get_pixel(idx + off, 120)
|
||||
avg = tuple(map(sum, zip(avg, rgb)))
|
||||
|
||||
if not t[i](avg[0] / 10, avg[1] / 10, avg[2] / 10):
|
||||
raise Exception(
|
||||
"COLOR BARS TEST FAILED."
|
||||
"BAR#(%d): RGB(%d,%d,%d)"
|
||||
% (i + 1, avg[0] / 10, avg[1] / 10, avg[2] / 10)
|
||||
)
|
||||
|
||||
print("COLOR BARS TEST PASSED...")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("")
|
||||
test_int_adc()
|
||||
test_color_bars()
|
||||
@ -1,48 +0,0 @@
|
||||
# This work is licensed under the MIT license.
|
||||
# Copyright (c) 2013-2023 OpenMV LLC. All rights reserved.
|
||||
# https://github.com/openmv/openmv/blob/master/LICENSE
|
||||
#
|
||||
# OpenMV Unit Tests.
|
||||
#
|
||||
import os
|
||||
import gc
|
||||
|
||||
TEST_DIR = "unittest"
|
||||
TEMP_DIR = "unittest/temp"
|
||||
DATA_DIR = "unittest/data"
|
||||
SCRIPT_DIR = "unittest/script"
|
||||
|
||||
if not (TEST_DIR in os.listdir("")):
|
||||
raise Exception("Unittest dir not found!")
|
||||
|
||||
print("")
|
||||
test_failed = False
|
||||
|
||||
|
||||
def print_result(test, result):
|
||||
s = "Unittest (%s)" % (test)
|
||||
padding = "." * (60 - len(s))
|
||||
print(s + padding + result)
|
||||
|
||||
|
||||
for test in sorted(os.listdir(SCRIPT_DIR)):
|
||||
if test.endswith(".py"):
|
||||
test_result = "PASSED"
|
||||
test_path = "/".join((SCRIPT_DIR, test))
|
||||
try:
|
||||
exec(open(test_path).read())
|
||||
gc.collect()
|
||||
if unittest(DATA_DIR, TEMP_DIR) is False:
|
||||
raise Exception()
|
||||
except Exception as e:
|
||||
if "unavailable" in str(e):
|
||||
test_result = "DISABLED"
|
||||
else:
|
||||
test_failed = True
|
||||
test_result = "FAILED"
|
||||
print_result(test, test_result)
|
||||
|
||||
if test_failed:
|
||||
print("\nSome tests have FAILED!!!\n\n")
|
||||
else:
|
||||
print("\nAll tests PASSED.\n\n")
|
||||
@ -33,7 +33,7 @@ from ml.preprocessing import Normalization
|
||||
|
||||
class Model(uml.Model):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, kwargs.get("load_to_fb", False))
|
||||
super().__init__(*args, kwargs.get("load_to_fb", False), kwargs.get("postprocess", False))
|
||||
try:
|
||||
path = args[0].split(".")[0] + ".txt"
|
||||
self.labels = [line.rstrip('\n') for line in open(path, "r")]
|
||||
|
||||
@ -195,3 +195,39 @@ def draw_predictions(
|
||||
color=box_color,
|
||||
)
|
||||
image.draw_string(x, y - font_height, label.upper(), text_color)
|
||||
|
||||
|
||||
def draw_keypoints(
|
||||
image,
|
||||
keypoints,
|
||||
radius=4,
|
||||
color=(255, 0, 0),
|
||||
thickness=1,
|
||||
fill=False,
|
||||
):
|
||||
|
||||
if radius > 0:
|
||||
for kp in keypoints:
|
||||
image.draw_circle(int(kp[0]), int(kp[1]), radius, color=color, thickness=thickness, fill=fill)
|
||||
elif radius == 0:
|
||||
for kp in keypoints:
|
||||
image.set_pixel(int(kp[0]), int(kp[1]), color)
|
||||
|
||||
|
||||
def draw_skeleton(
|
||||
image,
|
||||
keypoints,
|
||||
lines,
|
||||
kp_radius=4,
|
||||
kp_color=(255, 0, 0),
|
||||
kp_thickness=1,
|
||||
kp_fill=False,
|
||||
line_color=(0, 255, 0),
|
||||
line_thickness=1,
|
||||
):
|
||||
draw_keypoints(image, keypoints, radius=kp_radius, color=kp_color, thickness=kp_thickness, fill=kp_fill)
|
||||
|
||||
for line in lines:
|
||||
image.draw_line(int(keypoints[line[0]][0]), int(keypoints[line[0]][1]),
|
||||
int(keypoints[line[1]][0]), int(keypoints[line[1]][1]),
|
||||
color=line_color, thickness=line_thickness)
|
||||
|
||||
@ -34,24 +34,26 @@ from ulab import numpy as np
|
||||
_NO_DETECTION = const(())
|
||||
|
||||
|
||||
class BlazeFace:
|
||||
_BLAZEFACE_CX = const(0)
|
||||
_BLAZEFACE_CY = const(1)
|
||||
_BLAZEFACE_CW = const(2)
|
||||
_BLAZEFACE_CH = const(3)
|
||||
_BLAZEFACE_KP = const(4)
|
||||
class mediapipe_detection_postprocess:
|
||||
_MEDIAPIPE_CX = const(0)
|
||||
_MEDIAPIPE_CY = const(1)
|
||||
_MEDIAPIPE_CW = const(2)
|
||||
_MEDIAPIPE_CH = const(3)
|
||||
_MEDIAPIPE_KP = const(4)
|
||||
|
||||
def __init__(self, threshold=0.6, anchors=None, nms_threshold=0.1, nms_sigma=0.1):
|
||||
def __init__(self, threshold=0.6, anchors=None, anchor_grid=None, scores=[], cords=[],
|
||||
nms_threshold=0.1, nms_sigma=0.1):
|
||||
self.threshold = threshold
|
||||
self.anchors = anchors
|
||||
self.scores = scores
|
||||
self.cords = cords
|
||||
|
||||
if self.anchors is None:
|
||||
self.anchors = np.empty((896, 2))
|
||||
anchor_count = sum((g * g) * d for g, d in anchor_grid)
|
||||
self.anchors = np.empty((anchor_count, 2))
|
||||
idx = 0
|
||||
|
||||
# Generate anchors for 16x16 grid with 2 duplicates and
|
||||
# 8x8 grid with 6 duplicates to match the model output size.
|
||||
for grid_size, scales in [(16, 2), (8, 6)]:
|
||||
for grid_size, scales in anchor_grid:
|
||||
for gy in range(grid_size):
|
||||
cy = (gy + 0.5) / grid_size
|
||||
for gx in range(grid_size):
|
||||
@ -69,16 +71,16 @@ class BlazeFace:
|
||||
nms = NMS(iw, ih, inputs[0].roi)
|
||||
output_len = outputs[0].shape[1]
|
||||
|
||||
self.blazeface_post_process(ih, iw, nms, model, inputs, outputs, 1, 0,
|
||||
self.detection_post_process(ih, iw, nms, model, inputs, outputs, self.scores[0], self.cords[0],
|
||||
self.threshold, self.anchors[:output_len])
|
||||
|
||||
if output_len < len(self.anchors):
|
||||
self.blazeface_post_process(ih, iw, nms, model, inputs, outputs, 2, 3,
|
||||
self.detection_post_process(ih, iw, nms, model, inputs, outputs, self.scores[1], self.cords[1],
|
||||
self.threshold, self.anchors[output_len:])
|
||||
|
||||
return nms.get_bounding_boxes(threshold=self.nms_threshold, sigma=self.nms_sigma)
|
||||
|
||||
def blazeface_post_process(self, ih, iw, nms, model, inputs, outputs, score_idx, cords_idx, t, anchors):
|
||||
def detection_post_process(self, ih, iw, nms, model, inputs, outputs, score_idx, cords_idx, t, anchors):
|
||||
s_oh, s_ow, s_oc = model.output_shape[score_idx]
|
||||
scale = model.output_scale[score_idx]
|
||||
t = quantize(model, logit(t), index=score_idx)
|
||||
@ -102,18 +104,18 @@ class BlazeFace:
|
||||
bb_a_array = np.take(anchors, score_indices, axis=0)
|
||||
|
||||
# Compute the bounding box information
|
||||
ax = bb_a_array[:, _BLAZEFACE_CX]
|
||||
ay = bb_a_array[:, _BLAZEFACE_CY]
|
||||
x_center = bb[:, _BLAZEFACE_CX] / iw + ax
|
||||
y_center = bb[:, _BLAZEFACE_CY] / ih + ay
|
||||
w_rel = bb[:, _BLAZEFACE_CW] / iw * 0.5
|
||||
h_rel = bb[:, _BLAZEFACE_CH] / ih * 0.5
|
||||
ax = bb_a_array[:, _MEDIAPIPE_CX]
|
||||
ay = bb_a_array[:, _MEDIAPIPE_CY]
|
||||
x_center = bb[:, _MEDIAPIPE_CX] / iw + ax
|
||||
y_center = bb[:, _MEDIAPIPE_CY] / ih + ay
|
||||
w_rel = bb[:, _MEDIAPIPE_CW] / iw * 0.5
|
||||
h_rel = bb[:, _MEDIAPIPE_CH] / ih * 0.5
|
||||
|
||||
# Get the keypoint information
|
||||
row_count = bb.shape[0]
|
||||
keypoints = np.empty((row_count, (c_oc - _BLAZEFACE_KP) // 2, 2))
|
||||
keypoints[:, :, 0] = (bb[:, _BLAZEFACE_KP::2] / iw + ax.reshape((row_count, 1))) * iw
|
||||
keypoints[:, :, 1] = (bb[:, _BLAZEFACE_KP + 1::2] / ih + ay.reshape((row_count, 1))) * ih
|
||||
keypoints = np.empty((row_count, (c_oc - _MEDIAPIPE_KP) // 2, 2))
|
||||
keypoints[:, :, 0] = (bb[:, _MEDIAPIPE_KP::2] / iw + ax.reshape((row_count, 1))) * iw
|
||||
keypoints[:, :, 1] = (bb[:, _MEDIAPIPE_KP + 1::2] / ih + ay.reshape((row_count, 1))) * ih
|
||||
|
||||
# Scale the bounding boxes to have enough integer precision for NMS
|
||||
xmin = (x_center - w_rel) * iw
|
||||
@ -123,3 +125,51 @@ class BlazeFace:
|
||||
|
||||
for i in range(bb.shape[0]):
|
||||
nms.add_bounding_box(xmin[i], ymin[i], xmax[i], ymax[i], bb_scores[i], 0, keypoints=keypoints[i])
|
||||
|
||||
|
||||
class BlazeFace(mediapipe_detection_postprocess):
|
||||
def __init__(self, threshold=0.6, anchors=None, nms_threshold=0.1, nms_sigma=0.1):
|
||||
super().__init__(threshold=threshold, anchors=anchors,
|
||||
anchor_grid=[(16, 2), (8, 6)], scores=[1, 2], cords=[0, 3],
|
||||
nms_threshold=nms_threshold, nms_sigma=nms_sigma)
|
||||
|
||||
|
||||
class BlazePalm(mediapipe_detection_postprocess):
|
||||
def __init__(self, threshold=0.6, anchors=None, nms_threshold=0.1, nms_sigma=0.1):
|
||||
super().__init__(threshold=threshold, anchors=anchors,
|
||||
anchor_grid=[(24, 2), (12, 6)], scores=[0], cords=[1],
|
||||
nms_threshold=nms_threshold, nms_sigma=nms_sigma)
|
||||
|
||||
|
||||
class HandLandmarks:
|
||||
def __init__(self, threshold=0.6, nms_threshold=0.1, nms_sigma=0.1):
|
||||
self.threshold = threshold
|
||||
self.nms_threshold = nms_threshold
|
||||
self.nms_sigma = nms_sigma
|
||||
|
||||
def __call__(self, model, inputs, outputs):
|
||||
ib, ih, iw, ic = model.input_shape[0]
|
||||
nms = NMS(iw, ih, inputs[0].roi)
|
||||
|
||||
score = outputs[2][0, 0]
|
||||
if score < self.threshold:
|
||||
return _NO_DETECTION
|
||||
|
||||
cords = outputs[3][0, :]
|
||||
|
||||
# Get the keypoint information
|
||||
keypoints = np.empty((len(cords) // 3, 3))
|
||||
keypoints[:, 0] = cords[0::3]
|
||||
keypoints[:, 1] = cords[1::3]
|
||||
keypoints[:, 2] = cords[2::3]
|
||||
|
||||
# Get bounding box information
|
||||
xmin = np.min(keypoints[:, 0])
|
||||
ymin = np.min(keypoints[:, 1])
|
||||
xmax = np.max(keypoints[:, 0])
|
||||
ymax = np.max(keypoints[:, 1])
|
||||
|
||||
left_right = outputs[0][0, 0] > 0.5
|
||||
|
||||
nms.add_bounding_box(xmin, ymin, xmax, ymax, score, left_right, keypoints=keypoints)
|
||||
return nms.get_bounding_boxes(threshold=self.nms_threshold, sigma=self.nms_sigma)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
scripts/unittest/data/compressed.jpeg
Normal file
BIN
scripts/unittest/data/compressed.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
scripts/unittest/data/csi.pgm
Normal file
BIN
scripts/unittest/data/csi.pgm
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user