| ## Copyright (c) 2020 The WebM project authors. All Rights Reserved. |
| ## |
| ## Use of this source code is governed by a BSD-style license |
| ## that can be found in the LICENSE file in the root of the source |
| ## tree. An additional intellectual property rights grant can be found |
| ## in the file PATENTS. All contributing project authors may |
| ## be found in the AUTHORS file in the root of the source tree. |
| ## |
| |
| #coding : utf - 8 |
| import numpy as np |
| import numpy.linalg as LA |
| import matplotlib.pyplot as plt |
| from Util import drawMF, MSE |
| """The Base Class of Estimators""" |
| |
| |
| class MotionEST(object): |
| """ |
| constructor: |
| cur_f: current frame |
| ref_f: reference frame |
| blk_sz: block size |
| """ |
| |
| def __init__(self, cur_f, ref_f, blk_sz): |
| self.cur_f = cur_f |
| self.ref_f = ref_f |
| self.blk_sz = blk_sz |
| #convert RGB to YUV |
| self.cur_yuv = np.array(self.cur_f.convert('YCbCr'), dtype=np.int) |
| self.ref_yuv = np.array(self.ref_f.convert('YCbCr'), dtype=np.int) |
| #frame size |
| self.width = self.cur_f.size[0] |
| self.height = self.cur_f.size[1] |
| #motion field size |
| self.num_row = self.height // self.blk_sz |
| self.num_col = self.width // self.blk_sz |
| #initialize motion field |
| self.mf = np.zeros((self.num_row, self.num_col, 2)) |
| |
| """estimation function Override by child classes""" |
| |
| def motion_field_estimation(self): |
| pass |
| |
| """ |
| distortion of a block: |
| cur_r: current row |
| cur_c: current column |
| mv: motion vector |
| metric: distortion metric |
| """ |
| |
| def block_dist(self, cur_r, cur_c, mv, metric=MSE): |
| cur_x = cur_c * self.blk_sz |
| cur_y = cur_r * self.blk_sz |
| h = min(self.blk_sz, self.height - cur_y) |
| w = min(self.blk_sz, self.width - cur_x) |
| cur_blk = self.cur_yuv[cur_y:cur_y + h, cur_x:cur_x + w, :] |
| ref_x = int(cur_x + mv[1]) |
| ref_y = int(cur_y + mv[0]) |
| if 0 <= ref_x < self.width - w and 0 <= ref_y < self.height - h: |
| ref_blk = self.ref_yuv[ref_y:ref_y + h, ref_x:ref_x + w, :] |
| else: |
| ref_blk = np.zeros((h, w, 3)) |
| return metric(cur_blk, ref_blk) |
| |
| """ |
| distortion of motion field |
| """ |
| |
| def distortion(self, mask=None, metric=MSE): |
| loss = 0 |
| count = 0 |
| for i in xrange(self.num_row): |
| for j in xrange(self.num_col): |
| if mask is not None and mask[i, j]: |
| continue |
| loss += self.block_dist(i, j, self.mf[i, j], metric) |
| count += 1 |
| return loss / count |
| |
| """evaluation compare the difference with ground truth""" |
| |
| def motion_field_evaluation(self, ground_truth): |
| loss = 0 |
| count = 0 |
| gt = ground_truth.mf |
| mask = ground_truth.mask |
| for i in xrange(self.num_row): |
| for j in xrange(self.num_col): |
| if mask is not None and mask[i][j]: |
| continue |
| loss += LA.norm(gt[i, j] - self.mf[i, j]) |
| count += 1 |
| return loss / count |
| |
| """render the motion field""" |
| |
| def show(self, ground_truth=None, size=10): |
| cur_mf = drawMF(self.cur_f, self.blk_sz, self.mf) |
| if ground_truth is None: |
| n_row = 1 |
| else: |
| gt_mf = drawMF(self.cur_f, self.blk_sz, ground_truth) |
| n_row = 2 |
| plt.figure(figsize=(n_row * size, size * self.height / self.width)) |
| plt.subplot(1, n_row, 1) |
| plt.imshow(cur_mf) |
| plt.title('Estimated Motion Field') |
| if ground_truth is not None: |
| plt.subplot(1, n_row, 2) |
| plt.imshow(gt_mf) |
| plt.title('Ground Truth') |
| plt.tight_layout() |
| plt.show() |