博客專欄

        EEPW首頁 > 博客 > 基于自動編碼器的賽車視角轉換與分割

        基于自動編碼器的賽車視角轉換與分割

        發布人:數據派THU 時間:2022-06-19 來源:工程師 發布文章

        來源:Deephub Imba

        本篇文章將介紹如何將賽道的圖像轉換為語義分割后鳥瞰圖的軌跡。


        如下所示,輸入圖像為:
        圖片
        輸出:
        圖片
        總結來說我們的任務是獲取輸入圖像,即前方軌道的前置攝像頭視圖,并構建一個鳥瞰軌道視圖,而鳥瞰軌道視圖會分割不同的顏色表示賽道和路面的邊界。
        僅僅從輸入圖像中提取出關于走向的信息是相當困難的,因為未來的許多軌道信息被壓縮到圖像的前20個像素行中。鳥瞰攝像頭能夠以更清晰的格式表達關于前方賽道的信息,我們可以更容易地使用它來規劃汽車的行為。
        在正常行駛時拍攝鳥瞰圖是非常難實現的,所以如果我們可以使用前置攝像頭的圖像重建這些鳥眼圖像,就能讓我們用更清晰信息來進行路徑的規劃。另一個好處是可以降低維度,有效地將整個圖像表示為一組32個數字,這比整個圖像占用的空間少得多。并且如果還可以使用這種低維數據作為強化學習算法的觀察空間。
        本文中利用一種叫做變分自動編碼器(VAEs)的工具來幫助我們完成這項任務。簡單地說,我們把圖像壓縮到32維的潛在空間,然后重建我們分割的鳥瞰圖。本文末尾的PyTorch代碼顯示了完整的模型代碼。
        圖片
        為了訓練這一點,我們從前置攝像頭和鳥類攝像頭收集了一系列圖像。然后用編碼器進行編碼,然后使用全連接的層將維度降低到目標大小,最后使用****用一系列反卷積層重建圖像。
        結果如下所示:
        圖片
        雖然我們可以在重建中看到一些噪聲,但它可以很好地捕捉到整體曲線。代碼如下:

        import cv2
        import tqdm
        import numpy as np
        import torch
        import torch.nn as nn
        import torch.nn.functional as F


        class BEVVAE(nn.Module):
          """Input should be (bsz, C, H, W) where C=3, H=42, W=144"""

          def __init__(self, im_c=3, im_h=95, im_w=512, z_dim=32):
              super().__init__()

              self.im_c = im_c
              self.im_h = im_h
              self.im_w = im_w

              encoder_list = [
                  nn.Conv2d(im_c, 32, kernel_size=4, stride=2, padding=1),
                  nn.ReLU(),
                  nn.Conv2d(32, 64, kernel_size=4, stride=2, padding=1),
                  nn.ReLU(),
                  nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1),
                  nn.ReLU(),
                  nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1),
                  nn.ReLU(),
                  nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1),
                  nn.ReLU(),
                  nn.Flatten(),
              ]
              self.encoder = nn.Sequential(*encoder_list)
              self.encoder_list = encoder_list
              sample_img = torch.zeros([1, im_c, im_h, im_w])
              em_shape = nn.Sequential(*encoder_list[:-1])(sample_img).shape[1:]
              h_dim = np.prod(em_shape)

              self.fc1 = nn.Linear(h_dim, z_dim)
              self.fc2 = nn.Linear(h_dim, z_dim)
              self.fc3 = nn.Linear(z_dim, h_dim)

              self.decoder = nn.Sequential(
                  nn.Unflatten(1, em_shape),
                  nn.ConvTranspose2d(
                      em_shape[0],
                      256,
                      kernel_size=4,
                      stride=2,
                      padding=1,
                      output_padding=(1, 0),
                  ),
                  nn.ReLU(),
                  nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, output_padding=(1, 0)),
                  nn.ReLU(),
                  nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, output_padding=(1, 0)),
                  nn.ReLU(),
                  nn.ConvTranspose2d(
                      64, 32, kernel_size=4, stride=2, padding=1, output_padding=(1, 0)
                  ),
                  nn.ReLU(),
                  nn.ConvTranspose2d(32, im_c, kernel_size=4, stride=2, padding=1, output_padding=(1, 0)),
                  nn.Sigmoid(),
              )

          def reparameterize(self, mu, logvar):
              std = logvar.mul(0.5).exp_()
              esp = torch.randn(*mu.size(), device=mu.device)
              z = mu + std * esp
              return z

          def bottleneck(self, h):
              mu, logvar = self.fc1(h), self.fc2(h)
              z = self.reparameterize(mu, logvar)
              return z, mu, logvar

          def representation(self, x):
              return self.bottleneck(self.encoder(x))[0]

          def encode_raw(self, x: np.ndarray, device):
              # assume x is RGB image with shape (bsz, H, W, 3)
              p = np.zeros([x.shape[0], 95, 512, 3], np.float)
              for i in range(x.shape[0]):
                  p[i] = x[i][190:285] / 255
              x = p.transpose(0, 3, 1, 2)
              x = torch.as_tensor(x, device=device, dtype=torch.float)
              v = self.representation(x)
              return v, v.detach().cpu().numpy()

          def squish_targets(self, x: np.ndarray) -> np.ndarray:
              # Take in target images and resize them
              p = np.zeros([x.shape[0], 95, 512, 3], np.float)
              for i in range(x.shape[0]):
                  p[i] = cv2.resize(x[i], (512, 95)) / 255
              x = p.transpose(0, 3, 1, 2)
              return x

          def encode(self, x):
              h = self.encoder(x)
              z, mu, logvar = self.bottleneck(h)
              return z, mu, logvar

          def decode(self, z):
              z = self.fc3(z)
              return self.decoder(z)

          def forward(self, x):
              # expects (N, C, H, W)
              z, mu, logvar = self.encode(x)
              z = self.decode(z)
              return z, mu, logvar

          def loss(self, bev, recon, mu, logvar, kld_weight=1.0):
              bce = F.binary_cross_entropy(recon, bev, reduction="sum")
              kld = -0.5 * torch.sum(1 + logvar - mu ** 2 - logvar.exp())
              return bce + kld * kld_weight


        以上代碼修是從L2R示例代碼進行了進一步修改,https://github.com/learn-to-race/l2r


        Pytorch中的VAE代碼來自:

        https://github.com/sksq96/pytorch-vae



        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: AI

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 邯郸市| 奎屯市| 巴中市| 喜德县| 阜康市| 元阳县| 策勒县| 乐安县| 玉树县| 邯郸县| 佛山市| 镇安县| 岳普湖县| 巴林左旗| 南和县| 珠海市| 蒙山县| 昭苏县| 汉沽区| 涞源县| 乐东| 剑川县| 崇阳县| 芜湖市| 鸡泽县| 黄平县| 响水县| 白山市| 长治县| 平南县| 乐陵市| 友谊县| 河源市| 长春市| 台北县| 太仆寺旗| 双柏县| 屯门区| 怀宁县| 锡林郭勒盟| 黔南|