Module dvt.batch
Annotators for extracting high-level metadata about the images in the input.
Expand source code
# -*- coding: utf-8 -*-
"""Annotators for extracting high-level metadata about the images in the input.
"""
from numpy import abs as npabs, mean, percentile, prod, zeros
from cv2 import cvtColor, calcHist, resize, COLOR_BGR2HSV
from .abstract import BatchAnnotator
class DiffAnnotator(BatchAnnotator):
"""Annotator for detecting differences between frames."""
def __init__(self, **kwargs):
self.quantiles = kwargs.get("quantiles", [])
self.size = kwargs.get("size", 32)
self.bins = kwargs.get("bins", 16)
def annotate_batch(self, batch):
"""Annotate the batch of frames with the difference annotator.
Args:
batch (FrameBatch): A batch of images to annotate.
Returns:
A list of dictionaries containing the video name, frame, average
value, and any requested quantile and histogram differences.
"""
output = {"frame": batch.get_frame_names()}
output["avg_value"] = _average_value_batch(batch)
for quant in self.quantiles:
key = "q{0:d}".format(quant)
output[key] = _l1_quantile(batch, quantile=quant, size=self.size)
key = "h{0:d}".format(quant)
output[key] = _hist_diffs(batch, quantile=quant, bins=self.bins)
return {"diff": output}
def _l1_quantile(batch, quantile=50, size=32):
"""Compute differences between subsequent frames in a batch."""
bsize = batch.bsize
msize = bsize + 1
assert msize <= batch.get_frames().shape[0]
simg = zeros((msize, size, size, 3))
for iran in range(msize):
fsmall = resize(batch.get_frames()[iran, :, :, :], (size, size))
fsmall_hsv = cvtColor(fsmall, COLOR_BGR2HSV)
simg[iran, :, :, :] = fsmall_hsv
norm = simg[slice(0, bsize), :, :, :] - simg[slice(1, bsize + 1), :, :, :]
return percentile(npabs(norm), q=quantile, axis=(1, 2, 3))
def _hist_diffs(batch, quantile=50, bins=16):
"""Compute differences between HSV histograms across a batch."""
bsize = batch.bsize
msize = bsize + 1
assert msize <= batch.get_frames().shape[0]
hist_vals = _hsv_hist(batch, msize, bins=bins)
norm = hist_vals[slice(0, bsize), :] - hist_vals[slice(1, bsize + 1), :]
norm = norm / prod(batch.get_frames().shape[1:4]) * 100
return percentile(npabs(norm), q=quantile, axis=(1))
def _hsv_hist(batch, msize, bins=16):
"""Compute histogram counts from a batch of images."""
hist_vals = zeros((msize, bins * 3))
for iran in range(msize):
hsv = cvtColor(batch.get_frames()[iran, :, :, :], COLOR_BGR2HSV)
for i in range(3):
hist = calcHist([hsv], [i], None, [bins], [0, 256]).flatten()
hist_vals[iran, slice(i * bins, (i + 1) * bins)] = hist
return hist_vals
def _average_value_batch(batch):
"""Compute the average value across a batch of images."""
img = batch.get_batch()
return mean(img, axis=(1, 2, 3))
Functions
def calcHist(images, channels, mask, histSize, ranges, hist, accumulate)
-
calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist . @overload
def cvtColor(src, code, dst, dstCn)
-
cvtColor(src, code[, dst[, dstCn]]) -> dst . @brief Converts an image from one color space to another. .
. The function converts an input image from one color space to another. In case of a transformation . to-from RGB color space, the order of the channels should be specified explicitly (RGB or BGR). Note . that the default color format in OpenCV is often referred to as RGB but it is actually BGR (the . bytes are reversed). So the first byte in a standard (24-bit) color image will be an 8-bit Blue . component, the second byte will be Green, and the third byte will be Red. The fourth, fifth, and . sixth bytes would then be the second pixel (Blue, then Green, then Red), and so on. .
. The conventional ranges for R, G, and B channel values are: . - 0 to 255 for CV_8U images . - 0 to 65535 for CV_16U images . - 0 to 1 for CV_32F images .
. In case of linear transformations, the range does not matter. But in case of a non-linear . transformation, an input RGB image should be normalized to the proper value range to get the correct . results, for example, for RGB \f$\rightarrow\f$ L*u*v* transformation. For example, if you have a . 32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will . have the 0..255 value range instead of 0..1 assumed by the function. So, before calling #cvtColor , . you need first to scale the image down: . @code . img *= 1./255; . cvtColor(img, img, COLOR_BGR2Luv); . @endcode . If you use #cvtColor with 8-bit images, the conversion will have some information lost. For many . applications, this will not be noticeable but it is recommended to use 32-bit images in applications . that need the full range of colors or that convert an image before an operation and then convert . back. .
. If conversion adds the alpha channel, its value will set to the maximum of corresponding channel . range: 255 for CV_8U, 65535 for CV_16U, 1 for CV_32F. .
. @param src input image: 8-bit unsigned, 16-bit unsigned ( CV_16UC… ), or single-precision . floating-point. . @param dst output image of the same size and depth as src. . @param code color space conversion code (see #ColorConversionCodes). . @param dstCn number of channels in the destination image; if the parameter is 0, the number of the . channels is derived automatically from src and code. .
. @see @ref imgproc_color_conversions def resize(src, dsize, dst, fx, fy, interpolation)
-
resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst . @brief Resizes an image. .
. The function resize resizes the image src down to or up to the specified size. Note that the . initial dst type or size are not taken into account. Instead, the size and type are derived from . thesrc
,dsize
,fx
, andfy
. If you want to resize src so that it fits the pre-created dst, . you may call the function as follows: . @code . // explicitly specify dsize=dst.size(); fx and fy will be computed from that. . resize(src, dst, dst.size(), 0, 0, interpolation); . @endcode . If you want to decimate the image by factor of 2 in each direction, you can call the function this . way: . @code . // specify fx and fy and let the function compute the destination image size. . resize(src, dst, Size(), 0.5, 0.5, interpolation); . @endcode . To shrink an image, it will generally look best with #INTER_AREA interpolation, whereas to . enlarge an image, it will generally look best with c#INTER_CUBIC (slow) or #INTER_LINEAR . (faster but still looks OK). .
. @param src input image. . @param dst output image; it has the size dsize (when it is non-zero) or the size computed from . src.size(), fx, and fy; the type of dst is the same as of src. . @param dsize output image size; if it equals zero, it is computed as: . \f[\texttt{dsize = Size(round(fxsrc.cols), round(fysrc.rows))}\f] . Either dsize or both fx and fy must be non-zero. . @param fx scale factor along the horizontal axis; when it equals 0, it is computed as . \f[\texttt{(double)dsize.width/src.cols}\f] . @param fy scale factor along the vertical axis; when it equals 0, it is computed as . \f[\texttt{(double)dsize.height/src.rows}\f] . @param interpolation interpolation method, see #InterpolationFlags .
. @sa warpAffine, warpPerspective, remap
Classes
class DiffAnnotator (**kwargs)
-
Annotator for detecting differences between frames.
Expand source code
class DiffAnnotator(BatchAnnotator): """Annotator for detecting differences between frames.""" def __init__(self, **kwargs): self.quantiles = kwargs.get("quantiles", []) self.size = kwargs.get("size", 32) self.bins = kwargs.get("bins", 16) def annotate_batch(self, batch): """Annotate the batch of frames with the difference annotator. Args: batch (FrameBatch): A batch of images to annotate. Returns: A list of dictionaries containing the video name, frame, average value, and any requested quantile and histogram differences. """ output = {"frame": batch.get_frame_names()} output["avg_value"] = _average_value_batch(batch) for quant in self.quantiles: key = "q{0:d}".format(quant) output[key] = _l1_quantile(batch, quantile=quant, size=self.size) key = "h{0:d}".format(quant) output[key] = _hist_diffs(batch, quantile=quant, bins=self.bins) return {"diff": output}
Ancestors
- BatchAnnotator
- abc.ABC
Methods
def annotate_batch(self, batch)
-
Annotate the batch of frames with the difference annotator.
Args
batch
:FrameBatch
- A batch of images to annotate.
Returns
A list of dictionaries containing the video name, frame, average value, and any requested quantile and histogram differences.
Expand source code
def annotate_batch(self, batch): """Annotate the batch of frames with the difference annotator. Args: batch (FrameBatch): A batch of images to annotate. Returns: A list of dictionaries containing the video name, frame, average value, and any requested quantile and histogram differences. """ output = {"frame": batch.get_frame_names()} output["avg_value"] = _average_value_batch(batch) for quant in self.quantiles: key = "q{0:d}".format(quant) output[key] = _l1_quantile(batch, quantile=quant, size=self.size) key = "h{0:d}".format(quant) output[key] = _hist_diffs(batch, quantile=quant, bins=self.bins) return {"diff": output}
Inherited members