微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我需要对弯曲的矩形进行透视变换

如何解决我需要对弯曲的矩形进行透视变换

有没有办法以某种方式旋转图像?我会向你解释:我不想要PictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone)意义上的旋转,或者如图所示的here,而是将一个弯曲的矩形定向到相机(被与相机齐平)。

我做了一个 drawing for this。这是从上面的视图。想象一下,您是站在 (0,0) 点并正在拍摄身体照片的人 (“Rechteck”)。我想将该图像旋转某个角度,例如 35°,因为您与身体成 35°(透视)。

我已经准备了一些源代码并进行了计算。 代码的工作原理如下:用户必须输入他到矩形中心的距离以及角度。在附图中,这是红线。您还需要知道矩形的宽度。该程序计算 x 和 y 坐标(x_vy_v)。程序计算从矩形的左边缘到右边缘的所有距离和角度。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace schiefes_Rechteck
{
    public partial class Form_Main : Form
    {
        /// <summary>
        /// entered angle in degrees 
        /// </summary>
        private Int16 eingegebener_Winkel_in_Grad;
        private UInt16 Radius_in_mm;
        /// <summary>
        /// Length of the rectangle in mm 
        /// </summary>
        private UInt16 Laenge_des_Rechtecks_in_mm;
        /// <summary>
        /// all distances [mm]
        /// </summary>
        private List<double> alle_Entfernungen = new List<double>();
        /// <summary>
        /// all angles [°]
        /// </summary>
        private List<double> alle_Winkel = new List<double>();
        public Form_Main()
        {
            InitializeComponent();
        }

        private void Form_Main_Load(object sender,EventArgs e)
        {
            this.BackColor = Color.FromArgb(148,148,109);
            this.Location = new Point(0,0);
            Button_Start.BackColor = Color.FromArgb(194,194,165);
            TextBox_Entfernung.Text = "1300";
            TextBox_Winkel.Text = "35";
            TextBox_Rechtecklaenge.Text = "503";
            if (System.IO.File.Exists(Application.StartupPath + "\\schiefes_Rechteck_Grafik.PNG"))
            {
                PictureBox1.Image = Image.FromFile(Application.StartupPath + "\\schiefes_Rechteck_Grafik.PNG");
            }
        }

        private void Form_Main_FormClosing(object sender,FormClosingEventArgs e)
        {
            if (PictureBox1.Image != null)
            {
                PictureBox1.Image.dispose();
            }
            if (PictureBox2.Image != null)
            {
                PictureBox2.Image.dispose();
            }
        }

        private void TextBox_Entfernung_TextChanged(object sender,EventArgs e)
        {
            if (!string.IsNullOrEmpty(TextBox_Entfernung.Text))
            {
                bool erfolgreich = UInt16.TryParse(TextBox_Entfernung.Text,out Radius_in_mm);
                if (erfolgreich)
                {
                    TextBox_Entfernung.ForeColor = Color.FromArgb(0,163,0);
                }
                else
                {
                    TextBox_Entfernung.ForeColor = Color.FromArgb(163,0);
                }
            }
        }

        private void TextBox_Winkel_TextChanged(object sender,EventArgs e)
        {
            if (!string.IsNullOrEmpty(TextBox_Winkel.Text))
            {
                bool erfolgreich = Int16.TryParse(TextBox_Winkel.Text,out eingegebener_Winkel_in_Grad);
                if (erfolgreich)
                {
                    TextBox_Winkel.ForeColor = Color.FromArgb(0,0);
                }
                else
                {
                    TextBox_Winkel.ForeColor = Color.FromArgb(163,0);
                }
            }
        }
      
        private void TextBox_Rechtecklaenge_TextChanged(object sender,EventArgs e)
        {
            if (!string.IsNullOrEmpty(TextBox_Rechtecklaenge.Text))
            {
                bool erfolgreich = UInt16.TryParse(TextBox_Rechtecklaenge.Text,out Laenge_des_Rechtecks_in_mm);
                if (erfolgreich)
                {
                    TextBox_Rechtecklaenge.ForeColor = Color.FromArgb(0,0);
                }
                else
                {
                    TextBox_Rechtecklaenge.ForeColor = Color.FromArgb(163,0);
                }
            }
        }

        private async void Button_Start_Click(object sender,EventArgs e)
        {
            ListBox1.Items.Clear();
            await Task.Run(() => Berechnung_aller_Werte());
        }

        private void Berechnung_aller_Werte()
        {
            alle_Entfernungen.Clear();
            alle_Winkel.Clear();

            double x_v,y_v; // Mitte des Rechtecks,davon die x-Koordinate und die y-Koordinate. 
            x_v = Radius_in_mm * Math.Cos((90.0 - (double)eingegebener_Winkel_in_Grad) * Math.PI / 180.0); //richtig
            y_v = Radius_in_mm * Math.Sin((90.0 - (double)eingegebener_Winkel_in_Grad) * Math.PI / 180.0); //richtig

            double alpha_in_Grad = 0.0;
            double Entfernung = 0.0;
            double halbe_Rechteckbreite = Laenge_des_Rechtecks_in_mm / 2.0;
            double Position_linker_Rand = x_v - halbe_Rechteckbreite; //richtig

            double Zaehler = 0.0;

            while (Zaehler < Laenge_des_Rechtecks_in_mm)
            {
                alpha_in_Grad = Math.atan((Position_linker_Rand + Zaehler) / y_v) * 180.0 / Math.PI;
                alle_Winkel.Add(alpha_in_Grad);
                Entfernung = Math.Sqrt(Math.Pow(Position_linker_Rand + Zaehler,2) + Math.Pow(y_v,2));
                alle_Entfernungen.Add(Entfernung);
                Zaehler += 1.0;
            }
            this.BeginInvoke((Action)(() => { ListBox1.Items.Add(Math.Round(alle_Entfernungen.Last(),0).ToString() + " mm"); ListBox1.Items.Add(Math.Round(alle_Winkel.Last(),0).ToString() + " °"); }));
        }
    }//Form
}

解决方法

如果您想要一个不弯曲的图像,即所有线条保持垂直或水平,那么图像所发生的一切就是从侧面看它的宽度会显得更小,而其高度将保持不变。

通过将您看到图像的视在角度(即图像中黄绿色线和粉红色线之间的角度)除以您站立时的相应角度来获得 x 轴的缩放因子就在图像的前面。这个因素的一个非常好的近似值就是 cos(36° * PI / 180),其中角度是与图像中红线的角度。

xScale = Math.Cos(angleToMidLineInDegrees * Math.PI / 180);
yScale = 1;

或者干脆

xScale = Math.Cos(angleToMidLineInRadians);
yScale = 1;

哪里

angleToMidLineInRadians = Math.ATan(x_redLine / y_v);

或一步

xScale = y_v / Math.Sqrt(x_redLine * x_redLine + y_v * y_v);

参见:关于 WolframAlpha 的 cos(arctan(x/y))


但是,在变换图像时,您必须进行逆变换(如 video 末尾所述),因为您要确定变换图像的像素。即,您将使用伪代码进行操作(其中 t 表示转换,没有 t 是原始坐标):

for (yt = 0 to height_t - 1; yt++) {
    for (xt = 0 to width_t - 1; xt++) {
        (x,y) = inverse_transformation(xt,yt);
        color_t = get_color(picture,x,y);
        draw(picture_t,xt,yt,color_t);
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。