사슬(길이=$L$, 질량=$M$)이 수직으로 바닥으로 떨어진다. 다 떨어지는 순간 바닥이 받는 힘은?

1. $Mg$

2. $2Mg$

3. $3Mg$

 

더보기
더보기

우선 떨어지는 부분은 사슬고리 사이의 마찰 등을 무시하면 오직 중력에 의해서 자유낙하한다. 사슬이 바닥에 닿을 때 바닥이 주는 충격력에( 바닥의 수직항력) 의해서 정지하게 된다. 따라서 떨어지는 부분(관심 대상은 떨어지고 있는 부분과 충격력에 의해서 순간 정지하는 미소 질량까지 포함된 계이다. 왜냐면 바닥의 충격력 $f$가 미소 질량에 외력으로 작용하기 때문임)에 작용하는 알짜힘은 자체의 중력과 바닥이 주는 충격력$(f)$이다. 떨어지는 부분의 질량 $m(t)$는 시간에 따라 계속 변하고, 자유낙하이므로 

$$y(t)=\frac{1}{2} gt^2,  \quad m(t)=\lambda (L- y)= \lambda (L -\frac{1}{2} gt^2 ) ,$$

로 주어진다. 운동방정식은(아래 방향=+)

$$ \frac{dp}{dt} = \sum F_y = m g - f(t).$$

이다. 그리고

$$ \frac{dp}{dt}= \frac{d(m v )}{dt} = \frac{dm}{dt} v + m \frac{ d v}{dt} = - \lambda g t^2 + m g $$

이므로 떨어지는 부분이 바닥으로부터 받는 충격력은

$$ -\lambda g^2 t^2 +  mg = mg - f(t) \quad \longrightarrow \quad f(t)=\lambda g^2 t^2.$$

사슬이 완전히 바닥에 떨어지는데 걸리는 시간은 $L$ 높이에서 자유낙하하는 데 걸린 시간

$$y=L\quad \longrightarrow \quad t=\sqrt{\frac{2L}{g}},$$

이므로 다 떨어지는 순간 $f$는 

$$ f(y=L) = \lambda g^2 \left(\sqrt{\frac{2L}{g}} \right)^2= 2\lambda g L = 2Mg. $$

이 순간 바닥에 작용하는 알짜힘은 $f$의 반작용과 이미 바닥에 정지한 사슬의 무게이므로

$$ F_{bot} = f(y=L) +Mg = 3Mg.$$

 

 

보다 직관적으로는 사슬의 떨어지는 끝부분이 바닥에 닿는 순간 속도가 유한한 값에서 0으로 변하므로 바닥으로부터 끊임없이 충격량을 받아야 한다. $dm$의 질량이 정지하려면 바닥이 제공해야 할 충격량 $dJ$은

$$dJ = dm (v-0) = (\lambda dy)v \quad \rightarrow \quad f = \frac{dJ}{dt} =\lambda \frac{dy}{dt} v = \lambda v^2.$$

다 내려오는 순간 사슬의 속력은 $v^2 = 2gL$ 이므로,  $f= \lambda (2gL) =2Mg$.

 

참고 영상: https://www.youtube.com/watch?v=hoU_9DGMfzs

 
728x90
Posted by helloktk
,

마찰이 없는 바닥에 놓인 경사면(질량: $M$)을 따라 물체(질량: $m$)가 내려온다. 물체가 내려가면 경사면도 움직인다. 물체의 경로로 적합한 것은? 단, 경사면에도 마찰이 없다.

  1. A
  2. B
  3. C

 

더보기

경사면에서 마찰도 없다면 물체가 받는 힘은 중력과 수직항력뿐이다. 이 수직항력의 반작용 때문에 경사면은 밀려나게 된다. 수평 방향을 $x$-축, 수직 방향을 $y$-축으로 잡고 FBD을 이용해서 물체와 경사면의 운동 방정식을 쓰면, 경사면을 내려오는 물체의 가속도는

\begin{align} \sum F_x &= N \sin \theta =   ma_x , \\ \sum F_y &= N \cos \theta -mg      = ma_y. \end{align}

경사면은 수평 방향 운동만 가능하므로 수평 가속도는

$$\sum F_x = - N \sin \theta =  M a_X.$$

물체가 경사면에서만 움직이므로 $x_1$, $y_1$, $x_2$가 완전히 독립적일 수 없다:

$$\tan \theta = \frac{y_1}{x_2-x_1} =\text{const}\quad \longrightarrow \ddot{y}_1 = (\ddot{x}_2-\ddot{x}_1) \tan \theta \\ \text{or} \quad a_y = ( a_X- a_x) \tan \theta.$$

수직항력 $N$, 물체의 수평/수직 가속도 $a_x= \ddot{x}_1$, $a_y = \ddot{y}_1$, 그리고 경사면의 수평 가속도 $a_X=\ddot{x}_2$에 대한 4개의 식이 주어졌다. 이것을 풀면(연립 방정식이므로 쉽다).

\begin{gather} N = mg \frac{\cos \theta}{1 + \frac{m}{M} \sin ^2 \theta }, \\ a_x = g\frac{\sin \theta \cos \theta}{1 + \frac{m}{M} \sin ^2 \theta}, \quad a_y = - g \frac{ \Big(1+ \frac{m}{M}\Big) \sin ^2 \theta }{1 + \frac{m}{M} \sin ^2 \theta}, \\ a_X   = -g \frac{\frac{m}{M}\sin \theta\cos \theta}{1+\frac{m}{M} \sin ^2 \theta} \end{gather}

을 얻는다. 수평 방향이나 수직 방향 운동 모두 등가속도이다.

$M \gg m$인 경우를 보면, 경사면이 고정되어 있을 때 수직항력과 같음을 알 수 있다: $N\rightarrow mg\cos \theta$.

물체는 직선의 경로를 따라 내려가는데 그 각도는

$$ \tan \phi = \frac{|a_y|}{|a_x|} = \Big( 1 + \frac{m}{M}\Big) \tan \theta=\text{const}$$

이므로 경사면의 각보다 더 크다. 이는 경사면이 왼쪽으로 밀리기 때문이다.

  1. 경사면과 같이 움직이는 관찰자가 볼 때 물체가 내려가는 가속도는?
  2. 다 내려왔을 때 물체와 경사면의 속력은?
  3. 다 내려왔을 때 물체와 경사면은 처음 수평 위치에서 얼마나 벗어났는가?

운동 방정식을 직접적으로 사용하지 않고 두 질문을 해결하는 방법은?

어려운 설명을 볼 수 있는 동영상:

youtu.be/xzKPlY4 Dnrw

 
728x90
Posted by helloktk
,

 

(* coordinate 벡터의 크기로 차원 결정한다: n=Length[vars]; *)

InverseMetric[g_] := Simplify[Inverse[g]]

ChristoffelSymbol[g_, vars_] := 
 Block[{n, ig, res}, n = Length[vars]; ig = InverseMetric[g];
  res = Table[(1/2) * Sum[ig[[i, s]] *

         (-D[g[[j, k]], vars[[s]]] + D[g[[j, s]], vars[[k]]] + D[g[[s, k]], vars[[j]]]), {s, 1, n}],

         {i, 1, n} , {j, 1, n} , {k, 1, n}];
  Simplify[res]]

RiemannTensor[g_, vars_] := 
 Block[{n, Chr, res}, n = Length[vars]; 
  Chr = ChristoffelSymbol[g, vars];
  res = Table[

    D[Chr[[i, k, m]], vars[[l]]] - D[Chr[[i, k, l]], vars[[m]]] + 
    Sum[Chr[[i, s, l]]*Chr[[s, k, m]], {s, 1, n}] - 
    Sum[Chr[[i, s, m]]*Chr[[s, k, l]], {s, 1, n}], 

     {i, 1, n} , {k, 1, n} , {l, 1, n} , {m, 1, n}];
  Simplify[res]]

RicciTensor[g_, vars_] := 
 Block[{n, Rie, res}, n = Length[vars]; Rie = RiemannTensor[g, vars];
  res = Table[
    Sum[Rie[[s, i, s, j]], {s, 1, n}], 

    {i, 1, n} , {j, 1, n}];
  Simplify[res]]

RicciScalar[g_, vars_] := 
 Block[{n, Ricci, ig, res}, n = Length[vars]; 
  Ricc = RicciTensor[g, vars]; ig = InverseMetric[g];
  res = Sum[ig[[s, i]] Ricc[[s, i]], {s, 1, n} , {i, 1, n}];
  Simplify[res]]

 

예제: 구대칭 metric

$$ds^2 = -e^{ 2\nu(r)} dt^2 + e^{2\lambda(r)} dr^2 + r^2 d\theta^2 + r^2 \sin^2 \theta d\varphi^2$$

 

vars = {t, r, \[Theta], \[Phi]};

g = {{-Exp[2 \[Nu][r]], 0, 0, 0}, {0, Exp[2 \[Lambda][r]], 0, 0}, {0, 
    0, r^2, 0}, {0, 0, 0, r^2 Sin[\[Theta]]^2}};

RicciTensor[g, vars]

 

결과:

 

 

728x90
Posted by helloktk
,

동일한 물체나 풍경이라도 촬영에 사용된 센서의 종류나 조명 조건 때문에 사진이 더 어둡거나 반대로 더 밝게 표현될 수 있다. 이런 경우 사진을 잘 찍힌 사진과 비교하여 보정하려면 어떤 기준을 가지고 작업을 해야 할까? 동일한 내용의 영상이라면 단순히 히스토그램을 늘리거나 줄이는 과정을 (histogram stretching) 사용할 수 있다. 그러나 같은 물체나 풍경을 담지 않은 기준 영상의 히스토그램과 같은 내용의 히스토그램을 되도록 사진을 조작하고 싶으면 histogram stretching으로는 안된다. 

 

입력 영상의 주어진 픽셀 값이 기준 영상의 어떤 픽셀 값에 해당하게 변환을 해야 하는가를 결정해야 한다. 변환 $f$는 두 영상의 픽셀 값의 확률분포를 보존하도록 만들어진다. 입력 영상의 히스토그램 구간 $(i-1, i]$이 기준 영상의 히스토그램 구간 $(f(i-1), f(i)]$으로 변환될 때 각각 구간에서 픽셀이 나타날 확률이 동일해야 한다. 영상에서 픽셀 값은 이산적이므로 확률보다는 확률의 누적합을 이용하는 것이 더 편리하다. 입력 영상의 히스토그램 구간 $[0, i]$에서 픽셀이 나타날 누적 확률과 같은 누적 확률을 주는 기준 영상의 히스토그램 구간이 $[0, k=f(i)]$일 때 

$$i(영상)\rightarrow k = f(i) (기준영상)$$

으로 변환하면 된다. 이 과정은 히스토그램 stretching에도 그대로 적용이 된다. 누적 히스토그램(cumulative histogram)은 주어진 픽셀 값까지 확률 합을 쉽게 구할 수 있게 하는 일종의 lookup table이다. cumulative histogram의 $i$-번째 값은 픽셀 값이 $0$부터 $i$까지 히스토그램의 누적합이기 때문이다. 따라서 히스토그램 매칭(histogram matching, histogram specification)은 같은 cumulative histogram의 값을 갖는 픽셀 값 사이의 변환을 의미한다. 두  영상의 픽셀 수가 같지 않은 경우에는 cumulative histogram를 쓸 수 없다. 이 경우에는 전체 픽셀 수로 정규화시킨 cumulative distribution function(cdf)을 사용하면 된다.

 

 

히스토그램 평탄화(histogram equalization)는 각 그레이 값이 나타날 확률이 균일한 기준 영상을 (즉, 1차 cumulative histogram이 직선인 영상) 사용한 히스토그램 매칭에 해당한다. 따라서 기준 영상이 필요하지 않는다. 

 

 

//map을 lookup table로 이용해서 영상을 변환할 수 있다.
void matchHistogram(int srcHist[256], int refHist[256], int map[256]) {
    double cumSrc[256], cumRef[256];
    cumSrc[0] = srcHist[0];
    cumRef[0] = refHist[0];
    for (int i = 1; i < 256; i++) {
        cumSrc[i] = cumSrc[i - 1] + srcHist[i];
        cumRef[i] = cumRef[i - 1] + refHist[i];
    }
    // normalize ==> make CDF; 두 비교 영상이 같은 크기가 아닐 수 있으므로 필요하다;
    for (int i = 0; i < 256; i++) {
        cumSrc[i] /= cumSrc[255];
        cumRef[i] /= cumRef[255];
    }
    // 두 비교영상의 cumulant histogram이 가장 가까운(같은) 픽셀끼리 변환한다;
    for (int i = 0; i < 256; i++) {
        int k = 255;  
        while (cumRef[k] > cumSrc[i]) k--;
        // nearest interpolation; 2022.02.11
        if ((cumSrc[i] - cumRef[k]) < (cumRef[k + 1] - cumSrc[i])) map[i] = k;
        else map[i] = k + 1;
    }
};

실제 사용은 grey 이미지인 경우:

더보기
int histogramSpec(BYTE *src, int ws, int hs, BYTE *ref, int wr, int hr, BYTE *out) {
    int srcHist[256] = {0}, refHist[256] = {0}, map[256];
    makeHistogram(src, ws, hs, srcHist);
    makeHistogram(ref, wr, hr, refHist);
    matchHistogram(srcHist, refHist, map);
    for (int k = ws * hs; k-- > 0;)
        out[k] = map[src[k]];
    return 1;
}

 

728x90
Posted by helloktk
,

Tarjan의 Union-Find algorithm을 이용해서 (이진) 이미지의 Connected Component Labeling을 구현한 코드이다. 이미지의 배경은 검정(0)으로 하고 전경은 0이 아닌 값이면 된다. 처음 각 전경에 해당하는 픽셀은 모두 root node로 만든다: parent 정보는 배열 label에 저장되고, root node에 대해서는 label[pos] = pos). 4방향 연결을 기준으로 하면 왼쪽(LEFT)이나 위쪽(TOP)의 픽셀과 연결이 되어 있으면 parent가 더 작은 root 번호를 갖도록 합병한다(UNION).  8-방향 연결인 경우에는 위-왼쪽(TOPLEFT), 위-오른쪽(TOPRIGHT)도 합병한다. 전체 픽셀에 대해서 조사가 끝나면 배열 label에는 각 픽셀의 root 번호가 저장된다. 자신의 위치 값이 label의 값과 같은 경우는 root 노드로 새로운 blob의 시작을 나타낸다.  label 배열에 기록된 root 번호는 합병과정에서 중간 번호가 빠질 수 있을 수 있다. 순차적 레이블링이 필요한 경우에는 배열 label을 다시 스캔해서 번호가 순차적으로 할당되도록 만든다. 

보통의 connected component labeling 알고리즘이 이미지를 두 번 스캔을 해야 하는데 반해 이 알고리즘은 한 번의 스캔만 필요하다. 물론 순차적인 레이블링을 원하면 parent table을 다시 조사해야 한다.

 

#define CCL_LEFT         (-1)
#define CCL_TOP          (-w)
#define CCL_TOPLEFT      (-1 - w)
#define CCL_TOPRIGHT     (1 - w)

#define CCL_BG            (-1)
// 두 노드 (a,b)를 합병함; find(and compress)와 union을 동시에;
#define UNION(a, b, label) {                    \
    int r0 = (a), r1 = (b), p;                  \
    while ((p = label[r0]) != r0) { r0 = p; }   \
    label[(a)] = p;                             \
    while ((p = label[r1]) != r1) { r1 = p; }   \
    label[(b)] = p;                             \
    if (r0 > r1)  label[r0] = r1;               \
    else          label[r1] = r0;               \
}                  
static int FindRoot(int node, int* parent) {
    if (node != parent[node]) parent[node] = FindRoot(parent[node], parent);
    return parent[node];
}
static void Union(int node1, int node2, int *parent) {
    int root1 = FindRoot(node1, parent);
    int root2 = FindRoot(node2, parent);
    if (root1 > root2) parent[root1] = root2;
    else parent[root2] = root1;
}
int ConnectedComponentLabel(BYTE *image, int w, int h, int label[]) {
    BYTE *q = &image[0] ;
    for (int y = 0, pos = 0; y < h; y++) {
        for (int x = 0; x < w; x++, pos++) {
            if (*q++) {                     // Foreground;
                label[pos] = pos;           // 초기 root = 현위치             
                if ((y > 0) && q[CCL_TOP]) 
                    UNION(pos, pos + CCL_TOP, label);         
                if ((x > 0) && q[CCL_LEFT]) 
                    UNION(pos, pos + CCL_LEFT, label);
#if defined (_EIGHTCONN_)
                if ((x + 1 < w) && (y > 0) && q[CCL_TOPRIGHT]) 
                    UNION(pos, pos + CCL_TOPRIGHT, label);
                if ((x > 0) && (y > 0) && q[CCL_TOPLEFT]) 
                    UNION(pos, pos + CCL_TOPLEFT, label);
#endif // _EIGHTCONN_
            } else 
                label[pos] = CCL_BG;        // BACKGROUND;
        }
    }
    // 합병과정에서 빈 레이블이 생길 수 있으므로 순차적 레이블을 같도록 정리(선택 사항);
    // label = -1은 배경임;
    int curlab = 0;                                // 0-부터 시작;
    for (int pos = 0 ; pos < w * h; pos++) {
        int r = label[pos];
        if (r == CCL_BG)   continue;               // background;
        else if (r == pos) label[pos] = curlab++;  // root: assign a new label;
        else               label[pos] = label[r];  // assign renewed parent's label.
    }  
    return (curlab);                               //배경 제외;
};

blog.naver.com/helloktk/ 에서 옮겼고, 출력 부분을 바꿈;

<CCL을 이용하여 DataMatrix-code를 검출하는 과정>

이진화된 QR 코드 이미지

 

connected component labeling with colors

 

<20000 성분의 체스보드에 대한 4-방향 연결 테스트;>

출력은 정수형으로 바꾸어야 한다.  8-방향 연결로 하면 1개 성분만 나온다.

 

8 방향 연결 조건에서는 1개
4 방향 연결 조건에서는 W * H / 2개
percolation simulator에 사용된 예: 위쪽이나 아래쪽에서 연결된 경로를 표시했다.

 

 

728x90
Posted by helloktk
,