如何使图像适合另一个图像

How to fit image into another image

我想使一张图片适合另一张图片的准确位置。因此我需要

  1. 找出图像中的区域 ()

  2. 将叠加图像缩放并适合原始图像文件。


例子

我的原始图片会有类似于白页的内容:

现在我必须找到白色矩形并将其替换为覆盖图像:


结果

结果应该是这样的:

我以为你能解出方程式,但如果你遇到困难,我可以告诉你如何解。

让我们看一下列出的前两行。它们是直线,因此可以用形式为

的方程表示
y = mx + c

其中 c 是 y 轴截距,m 是线的梯度。

因此,对于第一行,截距或 c 显然是 198,因为它在那里穿过 x 轴。如果我们输入一些其他值(我会忽略小数,因为它们只会混淆概念)你会得到

63 = 1280m + 198

所以,第一行的等式是

y = -135x  + 198
    -----
     1280

第二条线可以使用相似三角形来获得 y 轴截距,或者 c 所以

 38   =  802
---      ---
720       c

这意味着

c = -802 * 720
    ----------
        38

如果我们将第二行列出的值再次放入公式中,我们会得到

720 = 840 m  - 802*720
               -------
                  32

这意味着

m=18.95

第二行的等式是

y=18.95x -15196

因此,如果我们将两个 y 值设置为相等,这一定是它们相遇的情况

-135x   + 198  = 18.95x - 15,196
-----
1280


-135x = 23,687x + 19,242,500

因此 x=807 并将其代入第 1 行的等式中,y=112。

因此前两条线相交于 112,807。

我让你做另外三个...

使用 Imagemagick (>6.8) 我可以使用以下命令或多或少地检测到白色矩形:

convert example.jpg -threshold 40% -canny 0x1+10%+30%    \
    \( +clone -background none                           \
              -fill red -stroke red -strokewidth 2       \
              -hough-lines 50x50+80 -write lines.mvg     \
    \) -composite result.png

它还 return 我的线坐标 (lines.mvg)。

# Hough line transform: 50x50+80
viewbox 0 0 1280 720
line 0,198.011 1280,63.4774  # 280
line 802.382,0 840.115,720  # 97
line 0,675.347 1280,518.183  # 238
line 138.716,0 201.708,720  # 191

稍后我想实现mark-setchell 建议的方程的解法。

您可以让 imagemagick 寻找交叉点...

convert example.jpg -threshold 40% -canny 0x1+10%+30%  \
  \( +clone -background none                           \
        -fill red -stroke red -strokewidth 1.2         \
            -hough-lines 50x50+80                      \
  \) -composite -fuzz 50% -fill black -opaque white    \
     -morphology HMT LineJunctions result2.png

就像这个例子,你不仅要寻找红点,还要寻找红色像素:

convert result2.png txt:- | egrep "red|srgb\(2[45][1234567890]"
# 808,112: (255,  0,  0)  #FF0000  red
# 807,113: (254,  0,  0)  #FE0000  srgb(254,0,0)
# 809,113: (254,  0,  0)  #FE0000  srgb(254,0,0)
# 155,183: (245,  0,  0)  #F50000  srgb(245,0,0)
# 832,572: (255,  0,  0)  #FF0000  red
# 196,652: (247,  0,  0)  #F70000  srgb(247,0,0)

现在是时候清理附近的点了...

points=`convert result2.png txt:- | egrep "red|srgb\(2[45][1234567890]" | sed -n 's/^\([0-9]*,[0-9]*\).*$//p'`
close=100

clean=()

distance()
{
    echo $(( ( - ) * ( - ) + ( - ) * ( - ) ))
}

while read x1 y1
do
    ok=1
    for point in "${clean[@]}"
    do
        echo "compare $x1 $y1 with $point"
        set -- $point
        if [[ $(distance $x1 $y1  ) -le $close ]]
        then
            ok=0
            break
        fi
    done
    if [ $ok = 1 ]
    then clean+=("$x1 $y1")
    fi
done < <( echo -e "$points" | tr ',' ' ' | sort -u )

echo "Clean:"
printf "%s\n" "${clean[@]}" | tr ' ' ','

edge_points=`printf "%s\n" "${clean[@]}" | tr ' ' ','`

并订购它们...

# get Center
centerx=0
centery=0
for point in $edge_points; 
do
    x=$(echo "$point" | cut -d, -f1)
        y=$(echo "$point" | cut -d, -f2)
    if [ $centerx -eq 0 ]
    then
        centerx=$((x))
        centery=$((y))
    else
        centerx=$(( centerx+x ))
        centery=$(( centery+y ))
    fi
    i=$((i+1))
done

centerx=$(( centerx/i ))
centery=$(( centery/i ))


centercircle="circle $((centerx-1)),$((centery-1)) $((centerx+1)),$((centery+1))"
echo "final center point $centercircle"

# Determine top-left, bottom-left, top-right, and bottom-right corner
top=()
bot=()

for point in $edge_points; 
do
    x=$(echo "$point" | cut -d, -f1)
        y=$(echo "$point" | cut -d, -f2)
    if [[ $y -le  $centery ]]
    then
        top+=("$x $y")
    else
        bot+=("$x $y")
    fi
done

echo "top points:"
printf "%s\n" "${top[@]}" | tr ' ' ','
echo "botten points:"
printf "%s\n" "${bot[@]}" | tr ' ' ','

top_points=`printf "%s\n" "${top[@]}" | tr ' ' ','`
bot_points=`printf "%s\n" "${bot[@]}" | tr ' ' ','`

[ $(echo ${top[0]} | cut -f1 -d ' ' ) -gt $(echo ${top[1]} | cut -f1 -d ' ' ) ] && tl=${top[1]} || tl=${top[0]}
[ $(echo ${top[0]} | cut -f1 -d ' ' ) -gt $(echo ${top[1]} | cut -f1 -d ' ' ) ] && tr=${top[0]} || tr=${top[1]}
[ $(echo ${bot[0]} | cut -f1 -d ' ' ) -gt $(echo ${bot[1]} | cut -f1 -d ' ' ) ] && bl=${bot[1]} || bl=${bot[0]}
[ $(echo ${bot[0]} | cut -f1 -d ' ' ) -gt $(echo ${bot[1]} | cut -f1 -d ' ' ) ] && br=${bot[0]} || br=${bot[1]}
echo "lt: $tl"
echo "lr: $tr"
echo "bl: $bl"
echo "br: $br"

clean_ordered=()
clean_ordered+=("$tl")
clean_ordered+=("$tr")
clean_ordered+=("$br")
clean_ordered+=("$bl")

edge_points=`printf "%s\n" "${clean_ordered[@]}" | tr ' ' ','`

# draw result
radius=2
nr=1    
circles=$(for point in $edge_points; do
          x=$(echo "$point" | cut -d, -f1)
          y=$(echo "$point" | cut -d, -f2)
          # use IM to do some floating point math, EG:  y2=$y+$radius
          y2=$(convert xc: -format '%[fx:'"$y"'+'"$radius"']' info:)
          echo "circle $x,$y $x,$y2"
        done)

echo "$circles"

text=$(for point in $edge_points; do
          x=$(echo "$point" | cut -d, -f1)
          y=$(echo "$point" | cut -d, -f2)
      x=$((x+5))
      y=$((y+5))
          echo "text $x,$y \"$nr\""
      nr=$((nr+1))
        done)

# Draw blue circles on the 4 points and the center point.
convert result2.png \
        -draw "fill none stroke blue $circles " \
        -draw "fill none stroke blue $centercircle" \
    -pointsize 20 \
    -draw "fill blue stroke blue $text " \
        result3.png

现在我们拥有最终合成图像所需的所有值。只是缺少一些变量:

points_a=`printf "%s\n" "${clean_ordered[0]}" | tr ' ' ','`
points_b=`printf "%s\n" "${clean_ordered[1]}" | tr ' ' ','`
points_c=`printf "%s\n" "${clean_ordered[2]}" | tr ' ' ','`
points_d=`printf "%s\n" "${clean_ordered[3]}" | tr ' ' ','`

orgi_size=$(identify -format "%[fx:w]x%[fx:h]" test/example.jpg)
owidth=$(identify -format "%[fx:w]" test/overly.png)
oheight=$(identify -format "%[fx:h]" test/overly.png)

现在可以得出最终的结果了,所以我们用-distort perspective的方法(就是第2题的答案):

convert \
    -verbose \
    example.jpg \
        \( overly.png \
        -background none \
        -gravity NorthWest  \
        -extent $orgi_size \
        -alpha set -virtual-pixel transparent \
        -distort Perspective "0,0 $points_a  $owidth,0 $points_b  $owidth,$oheight $points_c  0,$oheight $points_d" \) \
    -composite result4.jpg