0

この連続区分多項式 C(t) によって定義される照度変化のパラメーターを決定する必要があります。ここで、f(t) は 2 つの境界点 (t1,c) と (t2,0) によって定義される 3 次曲線です。 )、また f'(t1)=0 および f'(t2)=0 です。 元の紙: テクスチャ一貫性のあるシャドウ除去

ここに画像の説明を入力

ここに画像の説明を入力

強度曲線は影の境界の法線からサンプリングされ、次のようになります。

各行はサンプルで、照度の変化を表示します。したがって、X は列の番号で、Y はピクセルの強度です。

ここに画像の説明を入力

私はこのような私の実際のデータを持っています (すべてのサンプルから平均化された 1 つのサンプル): ここに画像の説明を入力

N 個のサンプルがあり、パラメーター (c、t1、t2) を決定する必要があります。

どうすればいいですか?

私はMatlabで一次方程式を解いてそれをやろうとしました:

avr_curve は、すべてのサンプルを平均して得られる平均曲線です。

f(x)= x^3+a2*x^2+a1*x1+a0 は 3 次関数です。

%t1,t2 selected by hand
t1= 10;
t2= 15;

offset=10;
avr_curve= [41, 40, 40, 41, 41, 42, 42, 43, 43, 43, 51, 76, 98, 104, 104, 103, 104, 105, 105, 107, 105];
%gradx= convn(avr_curve,[-1 1],'same');

A= zeros(2*offset+1,3);
%b= zeros(2*offset+1,1);
b= avr_curve';
%for i= 1:2*offset+1
for i=t1:t2
  i
  x= i-offset-1
  A(i,1)=  x^2; %a2
  A(i,2)=  x; %a1
  A(i,3)=  1; %a0 
  b(i,1)= b(i,1)-x^3;
end

u= A\b;

figure,plot(avr_curve(t1:t2))


%estimated cubic curve
for i= 1:2*offset+1 
  x= i-offset-1;
  fx(i)=x^3+u(1)*x^2+u(2)*x+u(3);
end

figure,plot(fx(t1:t2))

[t1 t2] の avr_curve の一部 ここに画像の説明を入力

私が得た 3 次曲線 (avr_curve のようには見えません) ここに画像の説明を入力

だから私は間違っているのですか?

更新: 私のエラーは、次のような 3 つの変数を使用して 3 次多項式をモデル化したことが原因のようです。

f(x)= x^3+a2*x^2+a1*x1+a0 - 3 variables

しかし、私は4つの変数を使用していますが、すべて問題ないようです:

f(x)= a3*x^3+a2*x^2+a1*x1+a0 - 4 variables 

Matlab のコードは次のとおりです。

%defined by hand
t1= 10;
t2= 14;

avr_curve= [41, 40, 40, 41, 41, 42, 42, 43, 43, 43, 51, 76, 98, 104, 104, 103, 104, 105, 105, 107, 105];
x=         [1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14,  15,  16,  17,  18,  19,  20,  21];
%x=        [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; %real x axis

%%%model 1
%%f(x)= x^3+a2*x^2+a1*x1+a0 - 3 variables
%A= zeros(4,3);
%b= [43  104]';
%%cubic equation at t1 
%A(1,1)= t1^2; %a2
%A(1,2)= t1; %a1
%A(1,3)= 1; %a0
%b(1,1)= b(1,1)-t1^3;
%%cubic equation at t2
%A(2,1)= t2^2; %a2
%A(2,2)= t2; %a1
%A(2,3)= 1; %a0
%b(2,1)= b(2,1)-t1^3;
%%1st derivative at t1
%A(3,1)= 2*t1; %a2
%A(3,2)= 1; %a1
%A(3,3)= 0; %a0
%b(3,1)= -3*t1^2;
%%1st derivative at t2
%A(4,1)= 2*t2; %a2
%A(4,2)= 1; %a1
%A(4,3)= 0; %a0
%b(4,1)= -3*t2^2;

%model 2
%f(x)= a3*x^3+a2*x^2+a1*x1+a0 - 4 variables
A= zeros(4,4);
b= [43  104]';
%cubic equation at t1 
A(1,1)= t1^3; %a3
A(1,2)= t1^2; %a2
A(1,3)= t1; %a1
A(1,4)= 1; %a0
b(1,1)= b(1,1);
%cubic equation at t2
A(2,1)= t2^3; %a3
A(2,2)= t2^2; %a2
A(2,3)= t2; %a1
A(2,4)= 1; %a0
b(2,1)= b(2,1);
%1st derivative at t1
A(3,1)= 3*t1^2; %a3
A(3,2)= 2*t1; %a2
A(3,3)= 1; %a1
A(3,4)= 0; %a0
b(3,1)= 0;
%1st derivative at t2
A(4,1)= 3*t2^2; %a3
A(4,2)= 2*t2; %a2
A(4,3)= 1; %a1
A(4,4)= 0; %a0
b(4,1)= 0;

size(A)
size(b)
u= A\b;
u

%estimated cubic curve
%dx=[1:21]; % global view
dx=t1-1:t2+1; % local view in [t1 t2]
for x= dx
  %fx(x)=x^3+u(1)*x^2+u(2)*x+u(3); % model 1
  fx(x)= u(1)*x^3+u(2)*x^2+u(3)*x+u(4); % model 2
end

err= 0;
for x= dx
  err= err+(fx(x)-avr_curve(x))^2;
end

err

figure,plot(dx,avr_curve(dx),dx,fx(dx))

間隔 [t1-1 t2+1​​] のスプライン ここに画像の説明を入力

そして完全な間隔で

ここに画像の説明を入力

4

1 に答える 1

2

免責事項

以下に示すコードまたはメソッドの正確性について保証することはできません。そのいずれかを使用する前に、常に批判的な感覚を使用してください。

0. 問題を定義する

この区分的に定義された関数があります

回復する区分関数

f(t)が 3 次関数である場合、それを一意に識別するために、次の追加条件が与えられます。

立方体の追加条件

与えられた点のセットで誤差を最小化するパラメーターt1t2、およびsigmaの最良の値を回復したいと考えています。

これは本質的に、最小二乗法の意味でのカーブ フィッティングです。

1 f(t) 3 次関数をパラメーター化する

候補のCl(t)関数とf(t)を計算する必要がある点のセットとの間の誤差を計算するには、その一般的な形式 (立方体) は次のとおりです。

ジェネラル キュービック

したがって、考慮すべき追加のパラメーターが 4 つあるようです。実際、このパラメーターは、自由な3 つのパラメーターt1t2、およびsigmaによって完全に定義されます。フリーパラメーターと従属パラメーターを
混同しないことが重要です。

f(t)に関する追加の条件が与えられると、この線形システムを設定できます。

立方体の線形システムを解く

によって与えられる(予想どおり)1つのソリューションがあります

立方体のパラメータ

これは、3 つの自由パラメーターが与えられたときに、3 次のパラメーターを計算する方法を教えてくれます。
このようにしてCl(t)が完全に決定されたので、次は最適な候補を見つけます。

2 エラーを最小限に抑える

私は通常、最小二乗法に行きます。
これは線形関数ではないため、sigmat1およびt2を計算するための閉じた形式はありません。ただし、 Gauss-Newton
のような数値的な方法もあります。

ただし、何らかの方法で、3 つのパラメーターに関して偏導関数を計算する必要があります。t1
のような分離パラメーターに関して導関数を計算する方法がわかりません。

MathSE を検索したところ、同じ問題に対処するこの質問が見つかりましたが、誰も答えませんでした。

偏導関数がなければ、最小二乗法は終わりです。

そこで、より実用的な方法をとり、C で総当り関数を実装しました。この関数は、パラメータのすべての可能なトリプレットを試して、最適な一致を返します。

3 ブルートフォース機能

問題の性質上、これはサンプル数でO (n^2) である ことが判明しました。

アルゴリズムは次のように進みます: サンプル セットを 3 つの部分に分割します。最初の部分はt1より前のポイントの部分、2 番目はt1t2の間のポイント、およびt2の後のポイントの最後の部分です。

最初の部分のみがsigmaの計算に使用され、sigmaは単純に部分 1 のポイントの算術平均です。

t1t2は 1 サイクルで計算され、t1は元のポイント セット内のすべての可能なポイントに設定されます。t1
を選択するたびに、t2はt1の後のすべての可能な点に設定されます。

各反復でエラーが計算され、これまでに見られた最小値である場合、使用されたパラメーターが保存されます。

誤差は残差の絶対値として計算されます。これは、絶対値が高速である必要があり (確実に 2 乗よりも高速)、メトリックの目的に適合するためです。

4 コード

#include <stdio.h>
#include <math.h>

float point_on_curve(float sigma, float t1, float t2, float t)
{
    float a,b,c,d, K;

    if (t <= t1)
        return sigma;

    if (t >= t2)
        return 0;

    K = (t1-t2)*(t1-t2)*(t1-t2);
    a = -2*sigma/K;
    b = 3*sigma*(t1+t2)/K;
    c = -6*sigma*t1*t2/K;
    d = sigma*t2*t2*(3*t1-t2)/K;

    return a*t*t*t + b*t*t + c*t + d;
}

float compute_error(float sigma, float t1, float t2, int s, int dx, int* data, int len)
{
    float error=0;
    unsigned int i;

    for (i = 0; i < len; i++)
        error += fabs(point_on_curve(sigma, t1, t2, s+i*dx)- data[i]);

    return error;
}

/* 
 * s is the starting time of the samples set
 * dx is the separation in time between two sample (a.k.a. sampling period)
 * data is the array of samples
 * len  is the number of samples
 * sigma, t1, t2 are pointers to output parameters computed
 *
 * return 1 if not enough (3) samples, 0 if everything went ok.
 */
int curve_fit(int s, int dx, int* data, unsigned int len, float* sigma, float* t1, float* t2)
{
    float l_sigma = 0;
    float l_t1, l_t2;
    float sum = 0;

    float min_error, cur_error;
    char error_valid = 0;

    unsigned int i, j;

    if (len < 3)
        return 1;

    for (i = 0; i < len; i++)
    {
        /* Compute sigma as the average of points <= i */
        sum += data[i];
        l_sigma = sum/(i+1);

        /* Set t1 as the point i+1 */
        l_t1 = s+(i+1)*dx;

        for (j = i+2; j < len; j++)
        {
            /* Set t2 as the points i+2, i+3, i+4, ... */
            l_t2 = s+j*dx;

            /* Compute the error */
            cur_error = compute_error(l_sigma, l_t1, l_t2, s, dx, data, len);

            if (cur_error < min_error || !error_valid)
            {
                error_valid = 1;
                min_error = cur_error;

                *sigma = l_sigma;
                *t1 = l_t1;
                *t2 = l_t2;
            }
        }
    }

    return 0;
}

int main()
{
    float sigma, t1, t2;
    int data[]={41, 40, 40, 41, 41, 42, 42, 43, 43, 43, 51, 76, 98, 104, 104, 103, 104, 105, 105, 107, 105};
    unsigned int len = sizeof(data)/sizeof(int);
    unsigned int i;


    for (i = 0; i < len; i++)
        data[i] -= 107;             /* Subtract the max */


    if (curve_fit(1,1,data, len, &sigma, &t1, &t2))
        printf("Not enough data!\n");
    else 
        printf("Parameters: sigma = %.3f, t1 = %.3f, t2 = %.3f\n", sigma, t1, t2);

    return 0;


}

Cl(t)は 0 を右限界として定義されていることに注意してください。したがって、コードはこれが事実であると想定しています。

これが、すべてのサンプルから最大値 (107) が差し引かれる理由です。最初に与えられたCl(t)の定義を使用しましたが、後でサンプルに偏りがあることに気付きました。

ここではコードを変更するつもりはありません。問題に別のパラメーターを簡単に追加して、必要に応じて手順を 1 からやり直すか、最大値を使用してサンプルを単純に変換できます。

コードの出力は

 Parameters: sigma = -65.556, t1 = 10.000, t2 = 14.000

垂直方向に -107 平行移動されていることを考慮して、与えられたポイント セットと一致します。

于 2015-07-13T13:52:08.073 に答える