在kotlin multiplatform的共享模块中集成Chaquopy 16.0,无法访问共享模块中的Python

问题描述 投票:0回答:1

我正在开发一个 kotlin 多平台应用程序。在此共享模块中,我想使用 numpy 包对某些 .pkl 文件进行操作。 我正在遵循提到的设置官方设置链接-Kotlin。 到目前为止我所做的是 项目设置.gradle.kts

rootProject.name = "Assignment"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

pluginManagement {
    repositories {
        google {
            mavenContent {
                includeGroupAndSubgroups("androidx")
                includeGroupAndSubgroups("com.android")
                includeGroupAndSubgroups("com.google")

            }
        }

        mavenCentral()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositories {
        google {
            mavenContent {
                includeGroupAndSubgroups("androidx")
                includeGroupAndSubgroups("com.android")
                includeGroupAndSubgroups("com.google")
            }
        }
        mavenCentral()
    }
}

include(":composeApp")
include(":shared")

项目-> build.gradle.kts

    plugins {
    // this is necessary to avoid the plugins to be loaded multiple times
    // in each subproject's classloader
    alias(libs.plugins.androidApplication) apply false
    alias(libs.plugins.androidLibrary) apply false
    alias(libs.plugins.composeMultiplatform) apply false
    alias(libs.plugins.composeCompiler) apply false
    alias(libs.plugins.kotlinMultiplatform) apply false
    id("com.chaquo.python") version "16.0.0" apply false
}

还有 共享-> build.gradle.kts

    import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
    alias(libs.plugins.kotlinMultiplatform)
    alias(libs.plugins.androidLibrary)
    id("com.chaquo.python")
}

kotlin {
    androidTarget {
        @OptIn(ExperimentalKotlinGradlePluginApi::class)
        compilerOptions {
            jvmTarget.set(JvmTarget.JVM_11)
        }
    }

    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "Shared"
            isStatic = true
        }
    }

    sourceSets {

        androidMain.dependencies {

        }
        iosMain.dependencies {

        }

        commonMain.dependencies {
            implementation(libs.multik.core)
            implementation(libs.multik.kotlin)

        }
    }
}

android {
    namespace = "com.assignment.shared"
    compileSdk = libs.versions.android.compileSdk.get().toInt()
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    defaultConfig {
        minSdk = libs.versions.android.minSdk.get().toInt()
        ndk {
            // On Apple silicon, you can omit x86_64.
            abiFilters += listOf("arm64-v8a")
        }
    }
}
chaquopy {
    defaultConfig {
        buildPython ("/usr/local/bin/python3")
    }
    productFlavors { }
    sourceSets { }
}

这些是配置文件。 我收到的第一个警告是

Warning: Failed to compile to .pyc format: [/usr/local/bin/python3] does not appear to be a valid Python command. See https://chaquo.com/chaquopy/doc/current/android.html#android-bytecode

我尝试通过终端访问 python3,它运行良好。

当我尝试在共享模块的类中导入 python 时,它不会被导入。 我该如何修复它并可以在我的 kmm 应用程序中访问 numpy 包?

编辑:如果有人想建议任何其他库或解决方法来对 KMM 项目中的 .pkl 文件进行操作。(iOS 和 Android)。 或者帮我将 python 脚本转换为 kotlin/multik 库。

    # -*- coding: utf-8 -*-

import numpy as np
import pickle


def seg_stride(sig, dz, f_start, est_t):
    """! Estimate stride start and end for walking segment

    @param sig Moving standard deviation of heel
    @param dz Depth difference between heels
    @param f_start Start frame of walking segment
    @param est_t Estimated duration of one stride
    @return fp_lr Estimated frames for stride [start, end]
    """
    cur_len = len(sig)
    m_thres = np.mean(sig[sig < np.median(sig)]) # get the mean for values less than median
    [idx] = np.where(np.diff((sig < m_thres) * 1) > 0) # the search start point for each stride, where the heel z goes below threshold
    
    # Filter idx such that there is only one in each stride
    # upward zero-crossings to nearest time step
    [upcross] = np.where((dz[:-1] <= 0) & (dz[1:] > 0))
    # downward zero-crossings
    [downcross] = np.where((dz[:-1] >= 0) & (dz[1:] < 0))
    if len(upcross) >= len(downcross):
        cross = upcross
    else:
        cross = downcross
    cross = np.concatenate([[0], cross, [cur_len]])
    filtered_idx = []

    # Iterate through the intervals in downcross
    for i in range(len(cross) - 1):
        start = cross[i]
        end = cross[i + 1]
        # Find elements in idx that are in the interval (start, end)
        elements_in_interval = idx[(idx >= start) & (idx < end)]
        # If there is exactly one element, keep it; otherwise, keep the smallest element
        if len(elements_in_interval) >= 1:
            filtered_idx.append(elements_in_interval[0])
    
    # Convert filtered_idx back to a numpy array
    filtered_idx = np.array(filtered_idx)

    num_fp = len(filtered_idx) # no. of strides

    if num_fp > 1:
        fp = np.zeros((num_fp))
        # refine and record the corresponding frame
        for k in range(num_fp):
            cur_t = filtered_idx[k]
            cur_sig = sig[cur_t : min(cur_len, cur_t + round(0.25 * est_t))] # search space for one stride, start point to 1/4 of estimated stride or end of vid

            # locate the local minimum
            s_idx = np.argmin(cur_sig)
            t2 = min(cur_len, cur_t + s_idx)
            t1 = max(0, cur_t - round(0.2 * est_t)) # what is this for?
            t_idx = np.argmax(dz[t1 : t2 + 1]) # checking step to see if there is an earlier peak?
            fp[k] = f_start + t1 + t_idx

        # set fp_left: each row is [start frame, end frame] of a valid stride
        fp_lr = np.zeros((num_fp - 1, 2), dtype=int)
        for k in range(num_fp - 1):
            fp_lr[k, 0] = int(fp[k])
            fp_lr[k, 1] = int(fp[k + 1])

    else:
        fp_lr = np.empty((0, 2), dtype=int)

    return fp_lr


def dist2plane_new(points, ground_plane):
    """! Project 3D points to plane and compute shortest distance

    @param points Input 3D points
    @param ground_plane ground plane parameters (a,b,c,d)
    @return projected_points Projected points on ground plane
    @return distance Shortest distance between points and plane
    """

    a, b, c, d = ground_plane

    projected_points = []
    distance = []
    for point in points:
        s, u, v = point
        t = (d - a * s - b * u - c * v) / (a * a + b * b + c * c)

        # point closest to plane
        x = s + a * t
        y = u + b * t
        z = v + c * t

        dist = abs(a * s + b * u + c * z + d) / (np.sqrt(a * a + b * b + c * c))
        projected_points.append([x, y, z])
        distance.append(dist)

    return np.array(projected_points), np.array(distance)


def refine_stride_boundary(angle, foot_on, cur_t, c_margin, nb_frames):
    # set local segment
    t1 = max(0, cur_t - c_margin)
    t2 = min(nb_frames - 1, cur_t + c_margin)

    # refine the start of stride by finding the  largest decrease in heel angle
    idx = local_argmin_diff(angle, t1, t2)
    t = t1 + idx

    # further refine by ensuring foot is on ground at t
    if t not in foot_on:
        # if foot not on ground, adjust to next frame when foot is on ground
        next_foot_on = foot_on[(foot_on - t)>0]
        if len(next_foot_on)>0:
            t = next_foot_on[0]

    return t


def find_boundaries(fp, angle, angle_other, foot_on, est_t, nb_frames):
    c_margin = round(est_t / 10)
    t = [] 

    # refine stride boundaries (foot on)
    for k in range(len(fp)):
        # refine start and end of stride
        t_start = refine_stride_boundary(angle, foot_on, fp[k, 0], c_margin, nb_frames)
        t_end = refine_stride_boundary(angle, foot_on, fp[k, 1], c_margin, nb_frames)
    
        # find foot offs
        if t_end >= t_start+4: # if next foot on is at least 4 frames ahead
            # find foot off - min angle between start and end of stride
            t_fo = t_start + local_argmin(angle, t_start, t_end)
            # if current foot off is at least 2 frames ahead of start
            if t_fo >= t_start+2: 
                # find other foot off
                to_fo = t_start + local_argmin(angle_other, t_start, t_fo)
                t.append([t_start, to_fo, t_fo, t_end])

    return t


def combine_left_right(fp1, fp2):
    # foot ons
    t_strides = [t[0] for t in fp2] + [t[-1] for t in fp2]
    t_strides = sorted(set(t_strides))
    t_strides = np.array(t_strides)
    refined_fp = []
    for fp in fp1:
        other_foot_on = t_strides[(t_strides>fp[1]) & (t_strides<fp[2])]
        if len(other_foot_on) == 1:
            refined_fp.append([fp[0], fp[1], other_foot_on[0], fp[2], fp[3]])
    return np.array(refined_fp)


def params_est_lidar(pose_data, fp_walk_list, ground_plane):
    """! Estimate gait parameters based on 3D pose data by identifying corresponding timestamps

    @param pose_data 3D pose data (28 key points) for
    ('L_HEAD'    'R_HEAD'    'SGL'    'CV7'    'TV10'
    'L_SAE'     'R_SAE'    'MID_L_HE'    'MID_R_HE'    'MID_L_SP'
    'MID_R_SP' 'L_IAS'    'R_IAS'    'MID_IPS'    'L_FLE'
    'R_FLE'    'L_FME'    'R_FME'    'L_FAL'    'R_FAL'
    'L_TAM'    'R_TAM'    'L_FCC'     'R_FCC'    'L_FM2'    'R_FM2'    'L_FM5'    'R_FM5')
    @param fps Video frame rate
    @param fp_walk_list List of walking segments [[start1, end1, start2, end2], [s1,e1,s2,e2],...]
    @param ground_plane ground plane parameters (a,b,c,d)

    @return t_left Corresponding consecutive timestamps for left cycle
    @return t_right Corresponding consecutive timestamps for right cycle
    @return estimated stride lengths: stride_left, stride_right
    @return gait parameters output
    """

    # set 3D points
    left_heel = pose_data[:, 22, :]  # L_FCC
    right_heel = pose_data[:, 23, :]  # R_FCC
    left_toe = pose_data[:, 24, :]  # L_FM2 (idx: 25)
    right_toe = pose_data[:, 25, :]  # R_FM2 (idx: 26)

    # get number of frames
    nb_frames = pose_data.shape[0]

    # finding boundaries of each stride
    # depth difference
    dz = right_heel[:, 2] - left_heel[:, 2]
    # upward zero-crossings to nearest time step
    [upcross] = np.where((dz[:-1] <= 0) & (dz[1:] > 0))
    # downward zero-crossings
    [downcross] = np.where((dz[:-1] >= 0) & (dz[1:] < 0))

    # estimate the duration of one stride
    diff_up = np.diff(upcross).tolist()
    diff_down = np.diff(downcross).tolist()
    est_t = np.median(diff_up + diff_down)
    print('The estimated duration of one stride is %d frames' % est_t)

    # use the 2D-based phase segmentation results to set walking segments (change on 02/07/2023)
    # take input list and run in loop for walk-turn-walk (22/01/2024)
    fp_left = []
    fp_right = []
    print("number of complete round of walk-forward, walk-backward: ", len(fp_walk_list))
    for fp_walk in fp_walk_list:
        f_start1 = fp_walk[0]
        f_end1 = fp_walk[1]
        f_start2 = fp_walk[2]
        f_end2 = fp_walk[3]

        # for 1st walking segment (walk towards camera)
        # for left foot
        sig1 = left_heel[f_start1 : f_end1 + 1, 2]  # relative-depth (05/Oct/2023)
        dz1 = dz[f_start1 : f_end1 + 1]
        fp1_left = seg_stride(sig1, dz1, f_start1, est_t)

        # for right foot
        sig2 = right_heel[f_start1 : f_end1 + 1, 2]  # relative-depth (05/Oct/2023)
        dz2 = -dz1
        fp1_right = seg_stride(sig2, dz2, f_start1, est_t)

        # for 2nd walking segment (walk away from camera)
        # for left foot
        sig1 = -left_heel[f_start2 : f_end2 + 1, 2]  # add negative
        dz1 = -dz[f_start2 : f_end2 + 1]
        fp2_left = seg_stride(sig1, dz1, f_start2, est_t)

        # for right foot
        sig2 = -right_heel[f_start2 : f_end2 + 1, 2]  # relative-depth (05/Oct/2023)
        dz2 = -dz1
        fp2_right = seg_stride(sig2, dz2, f_start2, est_t)

        fp_left.append(fp1_left)
        fp_left.append(fp2_left)
        fp_right.append(fp1_right)
        fp_right.append(fp2_right)
    #print('Finished for loop')
    fp_left = np.vstack(fp_left)
    fp_right = np.vstack(fp_right)

    # Further processing to identify single support, double support, and refine stride boundaries
    #print('Starting Step3')
    # Step 3: Calculate distance to plane and angles between foot and floor

    # angle between left foot and floor plane
    [pp1, dz1] = dist2plane_new(left_heel, ground_plane)
    [pp2, dz2] = dist2plane_new(left_toe, ground_plane)
    perpendicular = dz2 - dz1 # height difference between left heel and toe relative to ground plane
    base = np.sqrt(np.sum(np.power(pp2 - pp1, 2), 1))  # distance between left heel and left toe
    left_angle = np.arctan2(perpendicular, base)
    left_angle = left_angle * 180 / np.pi  # convert to degree
    
    # angle between right foot and floor plane
    [pp1, dz1] = dist2plane_new(right_heel, ground_plane)
    [pp2, dz2] = dist2plane_new(right_toe, ground_plane)
    perpendicular = dz2 - dz1
    base = np.sqrt(np.sum(np.power(pp2 - pp1, 2), 1))
    right_angle = np.arctan2(perpendicular, base)
    right_angle = right_angle * 180 / np.pi  # convert to degree

    # distance between ankles and floor
    [ppl, dzl] = dist2plane_new(left_heel, ground_plane)
    [ppr, dzr] = dist2plane_new(right_heel, ground_plane)
    # compute when each foot is on ground
    left_foot_on = np.where(dzl < dzr)[0]
    right_foot_on = np.where(dzr < dzl)[0]

    #print('Starting Step4')
    # Step 4: refine boundaries of each stride and further divide into
    # double support (DS1), single support, and double support (DS2)

    # refine stride boundaries (foot on) and find foot offs
    t_left = find_boundaries(fp_left, left_angle, right_angle, left_foot_on, est_t, nb_frames)
    t_right = find_boundaries(fp_right, right_angle, left_angle, right_foot_on, est_t, nb_frames)

    # combine left and right times
    t_left = combine_left_right(t_left, t_right)
    t_right = combine_left_right(t_right, t_left)

    return t_left, t_right  # , stride_left, stride_right, output

def local_argmin(sig, start, end):
    """! Find local minimum index

    @param sig Signal
    @return Local minimum index
    """
    if end <= start:
        idx = 0
    else:
        idx = np.argmin(sig[start : end + 1])
    
    return idx

def local_argmin_diff(sig, start, end):
    """! Find local minimum index of difference

    @param sig Signal
    @return Local minimum index
    """
    if end <= start:
        idx = 0
    else:
        idx = np.argmin(np.diff(sig[start : end + 1]))
    
    return idx

with open('input_output/in3.pkl','rb') as file:
    data = pickle.load(file) 

print(f'{data}')
pose_data_3d_norm = data['pose_data_3d_norm']
fp_walk = data['fp_walk']
ground_plane = data['ground_plane']

[t_left, t_right] = params_est_lidar(pose_data_3d_norm, fp_walk, ground_plane)
python python-3.x numpy kotlin-multiplatform chaquopy
1个回答
0
投票

可以在 Kotlin 多平台项目中使用 Chaquopy,但由于 Chaquopy 仅支持 Android,因此必须以 Android 特定的方式进行配置,并且只能在应用程序的 Android 版本中使用。

对于此特定错误,您似乎已将其配置为使用

/usr/local/bin/python3
处的 Python 可执行文件,但不存在这样的路径。尝试删除
buildPython
行并让 Chaquopy 自动查找 Python。如果这不起作用,请将其设置为有效路径。

© www.soinside.com 2019 - 2024. All rights reserved.