0

この質問が以前にここここで尋ねられたことは知っていますが、残念ながら、提供された回答では私の問題を解決できませんでした。C# アプリケーションでStasm ( http://www.milbo.users.sonic.net/stasm/index.html ) ライブラリを使用しています。以下は、「AsmSearchDll」関数を呼び出すための私のコードです。

        [DllImport(@"stasm\stasm_dll.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern void AsmSearchDll
    (
        [Out] out Int32 pnlandmarks,
        [Out] out Int32[] landmarks,
        [In, MarshalAs(UnmanagedType.LPStr)] String image_name,
        [In, MarshalAs(UnmanagedType.LPStr)] String image_data,
        [In] Int32 width,
        [In] Int32 height,
        [In] Int32 is_color,
        [In, MarshalAs(UnmanagedType.LPStr)] String conf_file0,
        [In, MarshalAs(UnmanagedType.LPStr)] String conf_file1
    );

    public void SearchFacialFeatures()
    {
        string image_name = "image-5.jpg"; // imagePath;
        var image = new Image<Bgr, byte>(image_name).Convert<Gray, byte>();

        int pnlandmarks = 0;
        var landmarks = new int[500];

        var imageData = Marshal.PtrToStringAnsi(image.MIplImage.imageData);
        int imgWidth = image.Width;
        int imgHeight = image.Height;
        int is_color = 1;
        string confile_file0 = Path.GetFullPath(@"data\mu-68-1d.conf");
        string config_file1 = Path.GetFullPath(@"data\mu-76-2d.conf");
        string sDataDir = @"\stasm\data";


        AsmSearchDll(out pnlandmarks, out landmarks, image_name, imageData, imgWidth, imgHeight, 1, null, null);

        MessageBox.Show(image_name);
    }

問題は、この行に到達するとアプリケーション プロセスが停止することです。

AsmSearchDll(out pnlandmarks, out landmarks, image_name, imageData, imgWidth, imgHeight, 0, null, null);

最初、アプリケーションは AsmSearchDll 関数が呼び出されるたびに終了しますが、コードをいじった後、停止しました。アプリケーションは起動しますが、AsmSearchDll 関数は処理されません。VS でコードを見てきたのでわかりました。関数の下のメッセージ ボックスには到達しません。

関数が内部エラーをスローしていると強く感じています。私にとって不幸な部分は、これが Interop/DllImport との最初の取引であるということです。

私の質問は、何が間違っているのか、この問題をどのように解決できるのかということです。私はこれを1日プラスしてきました。

編集:管理されていない関数のコードを追加

アンマネージ関数のシグネチャ

void AsmSearchDll (
int *pnlandmarks,          // out: number of landmarks, 0 if can't get landmarks
int landmarks[],           // out: the landmarks, caller must allocate
const char image_name[],   // in: used in internal error messages, if necessary
const char image_data[],   // in: image data, 3 bytes per pixel if is_color
const int width,           // in: the width of the image
const int height,          // in: the height of the image
const int is_color,        // in: 1 if RGB image, 0 if grayscale
const char conf_file0[],   // in: 1st config filename, NULL for default
const char conf_file1[])   // in: 2nd config filename, NULL for default, "" if none

関数を呼び出す C++ の例

    const char *image_name = "../data/test-image.jpg";

IplImage *img = cvLoadImage(image_name, CV_LOAD_IMAGE_COLOR);
if(img == NULL) {
    printf("Error: Cannot open %s\n", image_name);
    return -1;
}
// sanity checks (AsmSearchDll assumes imageData is vector of b,r,g bytes)

if(img->nChannels != 3 || img->depth != IPL_DEPTH_8U ||
        img->origin != 0 || img->widthStep != 3 * img->width) {
    printf("Error: %s is an unrecognized image type\n", image_name);
    return -1;
}

// locate the facial landmarks with stasm

int nlandmarks;
int landmarks[500]; // space for x,y coords of up to 250 landmarks
AsmSearchDll(&nlandmarks, landmarks,
             image_name, img->imageData, img->width, img->height,
             1 /* is_color */, NULL /* conf_file0 */, NULL /* conf_file1 */);

ご協力いただきありがとうございます。

4

2 に答える 2

2

次の定義を使用します。

[DllImport(@"stasm\stasm_dll.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
internal static extern void AsmSearchDll
(
    [Out] out Int32 pnlandmarks,
    [Out] Int32[] landmarks,       // <-- the `out` keyword is removed
    [In, MarshalAs(UnmanagedType.LPStr)] String image_name,
    [In] IntPtr image_data,        // <-- should not be passed as string
    [In] Int32 width,
    [In] Int32 height,
    [In] Int32 is_color,
    [In, MarshalAs(UnmanagedType.LPStr)] String conf_file0,
    [In, MarshalAs(UnmanagedType.LPStr)] String conf_file1
);

out主な問題は冗長なキーワード onだったと思います。これにより、パラメーターが array へlandmarksのポインターとして渡されます。これは、 int へのポインターへのポインターを意味します。必要なのはint へのポインタです。

また、バイト配列を文字列として渡すと、バイト (image_dataパラメーター) の内容が破損する可能性があります。Marshal.PtrToStringAnsiこれで、関数を使用する必要がなくなりました。image.MIplImage.imageData関数に直接渡します。

うまくいくかどうか教えてください。私はそれをテストすることはできません。

于 2013-04-24T11:42:05.510 に答える
0

あなたの問題は、プログラムが ../data/%filename% で特定のファイルを検索しようとしていることです。これにより、Debug フォルダーと Release フォルダーを含む bin フォルダー内が検索され、作業ディレクトリは構成に応じて実際には Debug または Release のいずれかになります。 . これが、プログラムがコード 0x01 とエラーを返す理由です。簡単な解決策は、必要なすべてのファイルを含むデータ フォルダーを Debug または Release フォルダーの親フォルダーにコピーすることです。これは、dll がそれらのフォルダーを検索するフォルダー パスを変更することによって行われます。

この問題は、パスがハードコーディングされているために発生します。

于 2015-07-03T04:04:50.690 に答える