PyraNet数据预处理

1、

     训练

local inp = crop(img, c, s, 0, self.inputRes)

     首先做crop,目的是crop成想要的形状,c是center的位置,s是scale的位置,0是旋转角度,输入分辨率是256

1.1 图像和尺度预处理

1)scaleFactor <2

scaleFactor 是什么呢?                            scaleFactor = (200 * scale) / res

说白了就是原图的高相对于256的大小是多少,如果小于2就设置为1,如果scaleFactor<2,就设置为scaleFactor=1,他的意思是这时候目标的小人并不是特别大,在原图中取的话256应该可以把人圈出来,不需要图像缩放到一个小图,在小图上面取,这就是他的意思,所以下面的这两行代码仅仅对于scaleFactor>2的情况下有用

local newSize = math.floor(math.max(ht,wd) / scaleFactor)
tmpImg = image.scale(img,newSize)

综合上面的分析

scaleFactor的作用是是不是需要缩放图像!!!!!!!!!!!!!!!!也即是不是在缩放后的图像上取人!!!!!!!!!!!!!!!!如果人不大,不需要缩放图像,设置其为1!!!!!!!!!!!!!!!!!!否则人很大的话,不改变它的值,将图像缩放!!!!!!!!!!!!!!!!!!!!!!!!!


2)

scaleFactor>2

    if scaleFactor < 2.0 then scaleFactor = 1

    else
        local newSize = math.floor(math.max(ht,wd) / scaleFactor)
        if newSize < 2 then
           -- Zoomed out so much that the image is now a single pixel or less
           if ndim == 2 then newImg = newImg:view(newImg:size(2),newImg:size(3)) end
           return newImg
        else
           tmpImg = image.scale(img,newSize)
           ht,wd = tmpImg:size(2),tmpImg:size(3)
        end
    end


定义一个新的newsize,  math.floor(math.max(ht,wd) / scaleFactor),目标也是让他在256左右,以便将人体缩放到这个大小

但是作者不是直接缩放人体,而是将图像进行缩放,假设一个人缩放到256需要缩小3倍,作者首先将图像缩小3倍,所以下面的

c,s都要缩小三倍

    local c,s = center:float()/scaleFactor, scale/scaleFactor
    local ul = M.transform({1,1}, c, s, 0, res, true)
    local br = M.transform({res+1,res+1}, c, s, 0, res, true)

这三句话是最关键的。如果scaleFactor>2了,这个时候表明图像中的人太大了,需要在缩小后的图像上取人上面已经将图像所放了,所以这里必须将c,s按照相同的比例缩放,在缩放后的图像上进行裁剪


1.2 正式裁剪

接下来是crop操作,根据下面的讲解,我们可以知道,ul是(0,0)点映射到原来的图中的坐标位置,br是(256,256)点映射到原来的图中的坐标位置,他的意思是用256*256讲一个人包住,那么返回到原图中的大小是多少呢?就是br-ul


通过实验可以发现,如果scaleFactor>2,通常br-ul是(255,256),(255,255),(256,255)这几个组合,而scaleFactor<2确实任意的大小,why?????????????

这是因为在获得变换矩阵的时候,s=1的缘故!!!!!!!!!!!!!!!!!!!!

简单解析一下!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

在getTransfrom函数中,


这仅仅是对于scaleFactor>2的情形成立,对于scaleFactor<2.出来的结果则五花八门

为什么这样做!!!!!!!!!!!!!!!!!!!!!!!!

我觉得既然scaleFactor很大了,就在上文中缩放了的图像上面去做,s=1也是合理的,因为图像已经缩放好了,反之,scaleFactor<2就需要在未缩放好的图像中切割了!!!!!!!!!

if scaleFactor >= 2 then br:add(-(br - ul - res)) end
    这句话是为了让br-ul是256的大小

    local pad = math.ceil(torch.norm((ul - br):float())/2 - (br[1]-ul[1])/2)
    if rot ~= 0 then ul:add(-pad); br:add(pad) end
这句话是为了定义旋转,打pad,暂且不管,因为此时crop操作旋转角度为0


    local old_ = {1,-1,math.max(1, ul[2]), math.min(br[2], ht+1) - 1,
                       math.max(1, ul[1]), math.min(br[1], wd+1) - 1}
这句话定义从原图中的哪一部分来剪切我们要的人

    local new_ = {1,-1,math.max(1, -ul[2] + 2), math.min(br[2], ht+1) - ul[2],
                       math.max(1, -ul[1] + 2), math.min(br[1], wd+1) - ul[1]}
这句话定义把旧图抠出来的人放在新图的什么位置

    

local newImg = torch.zeros(img:size(1), br[2] - ul[2], br[1] - ul[1])
这句话定义了新的图像大小,如果是scaleFactor>2,是256*256,否则的话就是m*n了。

if not pcall(function() newImg:sub(unpack(new_)):copy(tmpImg:sub(unpack(old_))) end) then 
end
从老图像中的区域拷贝过来复制到新的图像的

if scaleFactor < 2 then newImg = image.scale(newImg,res,res) end

之前会担心,scaleFactor<2的时候,如果经过transform得到的变换区域大于了256*256是不是就把一些身体部位切没了???当然不会,因为上面的newImg的大小是br-ul, 保证了把整个人切进去,然后一个image.scale将图像缩放到256*256

function M.crop2(img, center, scale, rot, res)
    local ndim = img:nDimension()
    if ndim == 2 then img = img:view(1,img:size(1),img:size(2)) end
    local ht,wd = img:size(2), img:size(3)
    local tmpImg,newImg = img, torch.zeros(img:size(1), res, res)
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    --local img_his = tmpImg
    local cc = center
    local ss = scale
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    -- Modify crop approach depending on whether we zoom in/out
    -- This is for efficiency in extreme scaling case
    --scale = scale[1]
    --print(type(scale))
    local scaleFactor = (200 * scale) / res
    --print(torch.type(scale))
    if scaleFactor < 2.0 then scaleFactor = 1


    else
        local newSize = math.floor(math.max(ht,wd) / scaleFactor)
        if newSize < 2 then
           -- Zoomed out so much that the image is now a single pixel or less
           if ndim == 2 then newImg = newImg:view(newImg:size(2),newImg:size(3)) end
           return newImg
        else
           tmpImg = image.scale(img,newSize)
           ht,wd = tmpImg:size(2),tmpImg:size(3)
        end
    end


    -- Calculate upper left and bottom right coordinates defining crop region
    local c,s = center:float()/scaleFactor, scale/scaleFactor
    local ul = M.transform({1,1}, c, s, 0, res, true)
    local br = M.transform({res+1,res+1}, c, s, 0, res, true)
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    local ul_his = ul
    local br_his = br
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    if scaleFactor >= 2 then br:add(-(br - ul - res)) end


    -- If the image is to be rotated, pad the cropped area
    local pad = math.ceil(torch.norm((ul - br):float())/2 - (br[1]-ul[1])/2)
    if rot ~= 0 then ul:add(-pad); br:add(pad) end


    -- Define the range of pixels to take from the old image
    local old_ = {1,-1,math.max(1, ul[2]), math.min(br[2], ht+1) - 1,
                       math.max(1, ul[1]), math.min(br[1], wd+1) - 1}
    -- And where to put them in the new image
    local new_ = {1,-1,math.max(1, -ul[2] + 2), math.min(br[2], ht+1) - ul[2],
                       math.max(1, -ul[1] + 2), math.min(br[1], wd+1) - ul[1]}


    -- Initialize new image and copy pixels over
    local newImg = torch.zeros(img:size(1), br[2] - ul[2], br[1] - ul[1])
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    local width_his = br[2] - ul[2]
    local height_his = br[1] - ul[1]
    local img_his = newImg
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    if not pcall(function() newImg:sub(unpack(new_)):copy(tmpImg:sub(unpack(old_))) end) then
       print("Error occurred during crop!")
       print(width_his)
       print(height_his)
       print(cc)
       print(ss)
       print(newImg:size())
       print(img_his:size())




    end

transform会首先通过getTransform获得变换矩阵t,然后通过变换矩阵t进行坐标变换,利用t的逆乘以坐标获得变换之后的坐标

通常的旋转变换矩阵是

t*x = x_new    x = inv(t)*x_new

通过这个函数可以发现它是已知变换后的点,求出原来的点在原来图中的位置,具体怎样做的看一下getTransform函数

function M.transform(pt, center, scale, rot, res, invert)
    local pt_ = torch.ones(3)
    pt_[1],pt_[2] = pt[1]-1,pt[2]-1

    local t = M.getTransform(center, scale, rot, res)
    if invert then
        t = torch.inverse(t)
    end
    local new_point = (t*pt_):sub(1,2)

    return new_point:int():add(1)
end
给出了一个人的center位置,一个人的尺度信息,旋转角度,和缩放后的分辨率

1)因为scale是h/200,所以这里的h = 人体矩形框的高

2)t是旋转矩阵

3)t[1][1],t[2][2],来确定将这个人变成256的大小需要的scale的大小

4)t[1][3],t[2][3]是为了将人体框的中心点平移到(128,128)


如果x=a,y=b,也即恰巧是中心点的位置,那么讲过矩阵平移缩放后就在(128,128)这一个点处,反过来,如果用

 x = inv(t)*x_new计算出来的就是对应到未缩放的原图的点的位置

5)旋转矩阵


M是绕着任意点旋转变换矩阵,任意点是(tx,ty),在这个程序里面是tx=128,ty=128,所以是绕着128,128旋转

function M.getTransform(center, scale, rot, res)
    local h = 200 * scale
    local t = torch.eye(3)

    -- Scaling
    t[1][1] = res / h
    t[2][2] = res / h

    -- Translation
    t[1][3] = res * (-center[1] / h + .5)
    t[2][3] = res * (-center[2] / h + .5)

    -- Rotation
    if rot ~= 0 then
        rot = -rot
        local r = torch.eye(3)
        local ang = rot * math.pi / 180
        local s = math.sin(ang)
        local c = math.cos(ang)
        r[1][1] = c
        r[1][2] = -s
        r[2][1] = s
        r[2][2] = c
        -- Need to make sure rotation is around center
        local t_ = torch.eye(3)
        t_[1][3] = -res/2
        t_[2][3] = -res/2
        local t_inv = torch.eye(3)
        t_inv[1][3] = res/2
        t_inv[2][3] = res/2
        t = t_inv * r * t_ * t
    end

    return t
end

6)综合以上,解析一下返回的矩阵t

t = t_inv * r * t_ * t
t*(x,y,1)首先通过平移缩放把整个人平移到以128,128为中心,缩放到256,256这个框可以把人框柱,然后将图像绕着128,128旋转,用t的逆乘以变换后的坐标就可以返回到原图中了

1.3

标签制作

drawGaussian(out[i], transform(torch.add(pts[i],1), c, s, 0, self.outputRes), self.gsize)

画高斯图

注意到了没有!!!!!!!!!!,此处只传进去了5个参数,


invert参数丢失了,why???????????????????????

因为画高斯图的时候需要把坐标对应到256*256的高斯图上面,他不是说是一个反变换的过程,相反他是一个变换的过程,将图像中位于c,尺度为s的这个人用256*256的框包住,各个点的坐标都映射到哪了

所以直接local new_point = (t*pt_):sub(1,2),此处的t不是变换矩阵的逆

function M.drawGaussian(img, pt, sigma)
    -- Draw a 2D gaussian
    -- Check that any part of the gaussian is in-bounds
    local tmpSize = math.ceil(3*sigma)
    local ul = {math.floor(pt[1] - tmpSize), math.floor(pt[2] - tmpSize)}
    local br = {math.floor(pt[1] + tmpSize), math.floor(pt[2] + tmpSize)}
    -- If not, return the image as is
    if (ul[1] > img:size(2) or ul[2] > img:size(1) or br[1] < 1 or br[2] < 1) then return img end
    -- Generate gaussian
    local size = 2*tmpSize + 1
    local g = image.gaussian(size)
    -- Usable gaussian range
    local g_x = {math.max(1, -ul[1]), math.min(br[1], img:size(2)) - math.max(1, ul[1]) + math.max(1, -ul[1])}
    local g_y = {math.max(1, -ul[2]), math.min(br[2], img:size(1)) - math.max(1, ul[2]) + math.max(1, -ul[2])}
    -- Image range
    local img_x = {math.max(1, ul[1]), math.min(br[1], img:size(2))}
    local img_y = {math.max(1, ul[2]), math.min(br[2], img:size(1))}
    assert(g_x[1] > 0 and g_y[1] > 0)
    img:sub(img_y[1], img_y[2], img_x[1], img_x[2]):cmax(g:sub(g_y[1], g_y[2], g_x[1], g_x[2]))
    return img
end

画高斯图的时候保证所有的点都在高斯图的范围之内,不在范围之内的剪切掉


1.4 疑问?

这样的封闭的变换和反变换真的就可以天衣无缝的对应上吗?神奇!!!再探究!!!

1.5旋转的部分待定




2、测试

做测试的时候会有什么不同呢?测试的时候肯定是不旋转的看一下代码,看下一章


  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值