Exemplo n.º 1
0
def mg_motiongrams(
        self,
        filtertype='Regular',
        thresh=0.05,
        blur='None',
        use_median=False,
        kernel_size=5,
        inverted_motiongram=False,
        equalize_motiongram=True):
    """
    Shortcut for `mg_motion` to only render motiongrams.

    Args:
        filtertype (str, optional): 'Regular' turns all values below `thresh` to 0. 'Binary' turns all values below `thresh` to 0, above `thresh` to 1. 'Blob' removes individual pixels with erosion method. Defaults to 'Regular'.
        thresh (float, optional): Eliminates pixel values less than given threshold. Ranges from 0 to 1. Defaults to 0.05.
        blur (str, optional): 'Average' to apply a 10px * 10px blurring filter, 'None' otherwise. Defaults to 'None'.
        use_median (bool, optional): If True the algorithm applies a median filter on the thresholded frame-difference stream. Defaults to False.
        kernel_size (int, optional): Size of the median filter (if `use_median=True`) or the erosion filter (if `filtertype='blob'`). Defaults to 5.
        inverted_motiongram (bool, optional): If True, inverts colors of the motiongrams. Defaults to False.
        equalize_motiongram (bool, optional): If True, converts the motiongrams to hsv-color space and flattens the value channel (v). Defaults to True.

    Outputs:
        `filename`_mgx.png: A horizontal motiongram of the source video.
        `filename`_mgy.png: A vertical motiongram of the source video.

    Returns:
        MgList(MgImage, MgImage): An MgList pointing to the output motiongram images.
    """

    # color-mismatch issue needs to be fixed with this one
    # motiongrams_ffmpeg(
    #     filename=self.filename,
    #     color=self.color,
    #     filtertype=filtertype,
    #     threshold=thresh,
    #     blur=blur,
    #     use_median=use_median,
    #     kernel_size=kernel_size,
    #     invert=inverted_motiongram)

    mg_motion(
        self,
        filtertype=filtertype,
        thresh=thresh,
        blur=blur,
        kernel_size=kernel_size,
        inverted_motiongram=inverted_motiongram,
        equalize_motiongram=equalize_motiongram,
        save_data=False,
        save_motiongrams=True,
        save_plot=False,
        save_video=False)

    return MgList(MgImage(self.of + '_mgx.png'), MgImage(self.of + '_mgy.png'))
Exemplo n.º 2
0
def mg_motiongrams(self,
                   filtertype='Regular',
                   thresh=0.05,
                   blur='None',
                   kernel_size=5,
                   inverted_motiongram=False,
                   equalize_motiongram=True):

    mg_motion(self,
              filtertype=filtertype,
              thresh=thresh,
              blur=blur,
              kernel_size=kernel_size,
              inverted_motiongram=inverted_motiongram,
              equalize_motiongram=equalize_motiongram,
              save_data=False,
              save_motiongrams=True,
              save_plot=False,
              save_video=False)

    return MgList(
        [MgImage(self.of + '_mgx.png'),
         MgImage(self.of + '_mgy.png')])
Exemplo n.º 3
0
def videograms_ffmpeg(self):
    """
    Usees FFMPEG as backend. Averages videoframes by axes, and creates two images of the horizontal-axis and vertical-axis stacks.
    In these stacks, a single row or column corresponds to a frame from the source video, and the index
    of the row or column corresponds to the index of the source frame.

    Outputs
    -------
    - `filename`_vgx.png

        A horizontal videogram of the source video.
    - `filename`_vgy.png

        A vertical videogram of the source video.

    Returns
    -------
    - list(MgImage, MgImage)

        A tuple with the string paths to the horizontal and vertical videograms respectively. 
    """

    width, height = get_widthheight(self.filename)
    framecount = get_framecount(self.filename)
    length = get_length(self.filename)

    outname = self.of + '_vgy.png'
    cmd = ['ffmpeg', '-y', '-i', self.filename, '-frames', '1', '-vf',
           f'scale=1:{height}:sws_flags=area,normalize,tile={framecount}x1', outname]
    ffmpeg_cmd(cmd, length, pb_prefix="Rendering horizontal videogram:")

    outname = self.of + '_vgx.png'
    cmd = ['ffmpeg', '-y', '-i', self.filename, '-frames', '1', '-vf',
           f'scale={width}:1:sws_flags=area,normalize,tile=1x{framecount}', outname]
    ffmpeg_cmd(cmd, length, pb_prefix="Rendering vertical videogram:")

    return MgList([MgImage(self.of+'_vgx.png'), MgImage(self.of+'_vgy.png')])
Exemplo n.º 4
0
def mg_motionplots(self,
                   filtertype='Regular',
                   thresh=0.05,
                   blur='None',
                   kernel_size=5,
                   unit='seconds'):

    mg_motion(self,
              filtertype=filtertype,
              thresh=thresh,
              blur=blur,
              kernel_size=kernel_size,
              unit=unit,
              save_data=False,
              save_motiongrams=False,
              save_plot=True,
              save_video=False)

    return MgImage(self.of + '_motion_com_qom.png')
Exemplo n.º 5
0
def mg_motionplots(
        self,
        filtertype='Regular',
        thresh=0.05,
        blur='None',
        kernel_size=5,
        unit='seconds',
        title=None):
    """
    Shortcut for `mg_motion` to only render motion plots.

    Args:
        filtertype (str, optional): 'Regular' turns all values below `thresh` to 0. 'Binary' turns all values below `thresh` to 0, above `thresh` to 1. 'Blob' removes individual pixels with erosion method. Defaults to 'Regular'.
        thresh (float, optional): Eliminates pixel values less than given threshold. Ranges from 0 to 1. Defaults to 0.05.
        blur (str, optional): 'Average' to apply a 10px * 10px blurring filter, 'None' otherwise. Defaults to 'None'.
        kernel_size (int, optional): Size of structuring element. Defaults to 5.
        unit (str, optional): Unit in QoM plot. Accepted values are 'seconds' or 'samples'. Defaults to 'seconds'.
        title (str, optional): Optionally add title to the plot. Defaults to None, which uses the file name as a title.

    Returns:
        MgImage: An MgImage pointing to the exported image (png) of the motion plots.
    """

    mg_motion(
        self,
        filtertype=filtertype,
        thresh=thresh,
        blur=blur,
        kernel_size=kernel_size,
        unit=unit,
        save_data=False,
        save_motiongrams=False,
        save_plot=True,
        plot_title=title,
        save_video=False)

    return MgImage(self.of + '_motion_com_qom.png')
Exemplo n.º 6
0
def mg_average_image(self, filename='', normalize=True):
    """
    Finds and saves an average image of an input video file.

    Parameters
    ----------
    - filename : str, optional

        Path to the input video file. If not specified the video file pointed to by the MgObject is used.
    - normalize : bool, optional

        Default is `True`. If `True`, normalizes pixel values in the output image.

    Outputs
    -------
    - `filename`_average.png

    Returns
    -------
    - MgImage

        A new MgImage pointing to the output '_average' image file.
    """

    if filename == '':
        filename = self.filename

    of, fex = os.path.splitext(filename)

    # Convert to avi if the input is not avi - necesarry for cv2 compatibility on all platforms
    if fex != '.avi':
        convert_to_avi(of + fex)
        fex = '.avi'
        filename = of + fex

    video = cv2.VideoCapture(filename)
    ret, frame = video.read()
    length = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
    if self.color == False:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    average = frame.astype(np.float) / length
    pb = MgProgressbar(total=length, prefix='Rendering average image:')
    ii = 0
    while (video.isOpened()):
        ret, frame = video.read()
        if ret == True:
            if self.color == False:
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            frame = np.array(frame)
            frame = frame.astype(np.float)
            average += frame / length
        else:
            pb.progress(length)
            break
        pb.progress(ii)
        ii += 1

    if self.color == False:
        average = cv2.cvtColor(average.astype(np.uint8), cv2.COLOR_GRAY2BGR)

    if normalize:
        average = average.astype(np.uint8)
        norm_average = np.zeros_like(average)
        norm_average = cv2.normalize(average, norm_average, 0, 255,
                                     cv2.NORM_MINMAX)
        cv2.imwrite(of + '_average.png', norm_average.astype(np.uint8))

    else:
        cv2.imwrite(of + '_average.png', average.astype(np.uint8))

    return MgImage(of + '_average.png')
Exemplo n.º 7
0
def videograms_ffmpeg(self):
    """
    Renders horizontal and vertical videograms of the source video using ffmpeg. Averages videoframes by axes, and creates two images of the horizontal-axis and vertical-axis stacks. In these stacks, a single row or column corresponds to a frame from the source video, and the index of the row or column corresponds to the index of the source frame.

    Outputs:
        `self.filename`_vgx.png
        `self.filename`_vgy.png

    Returns:
        MgList(MgImage, MgImage): An MgList with the MgImage objects referring to the horizontal and vertical videograms respectively. 
    """

    width, height = get_widthheight(self.filename)
    framecount = get_framecount(self.filename)

    def calc_skipfactor(width, height, framecount):
        """
        Helper function to calculate the necessary frame-skipping to avoid integer overflow. This makes sure that we can succesfully create videograms even on many-hours-long videos as well.

        Args:
            width (int): The width of the video.
            height (int): The height of the video.
            framecount (int): The number of frames in the video.

        Returns:
            list(int, int): The necessary dilation factors to apply on the video for the horizontal and vertical videograms, respectively.
        """

        intmax = 2147483647
        skipfactor_x = int(
            math.ceil(framecount * 8 / (intmax / (height + 128) - 1024)))
        skipfactor_y = int(
            math.ceil(framecount / (intmax / ((width * 8) + 1024) - 128)))
        return skipfactor_x, skipfactor_y

    testx, testy = calc_skipfactor(width, height, framecount)

    if testx > 1 or testy > 1:
        necessary_skipfactor = max([testx, testy])
        print(
            f'{os.path.basename(self.filename)} is too large to process. Applying minimal skipping necessary...'
        )

        skip_frames_ffmpeg(self.filename, skip=necessary_skipfactor - 1)

        shortened_file = self.of + '_skip' + self.fex
        framecount = get_framecount(shortened_file)
        length = get_length(shortened_file)

        outname = self.of + '_skip_vgy.png'
        cmd = [
            'ffmpeg', '-y', '-i', shortened_file, '-vf',
            f'scale=1:{height}:sws_flags=area,normalize,tile={framecount}x1',
            '-aspect', f'{framecount}:{height}', '-frames', '1', outname
        ]
        ffmpeg_cmd(cmd,
                   length,
                   stream=False,
                   pb_prefix="Rendering horizontal videogram:")

        outname = self.of + '_skip_vgx.png'
        cmd = [
            'ffmpeg', '-y', '-i', shortened_file, '-vf',
            f'scale={width}:1:sws_flags=area,normalize,tile=1x{framecount}',
            '-aspect', f'{width}:{framecount}', '-frames', '1', outname
        ]
        ffmpeg_cmd(cmd,
                   length,
                   stream=False,
                   pb_prefix="Rendering vertical videogram:")

        return MgList([
            MgImage(self.of + '_skip_vgx.png'),
            MgImage(self.of + '_skip_vgy.png')
        ])

    else:
        length = get_length(self.filename)

        outname = self.of + '_vgy.png'
        cmd = [
            'ffmpeg', '-y', '-i', self.filename, '-frames', '1', '-vf',
            f'scale=1:{height}:sws_flags=area,normalize,tile={framecount}x1',
            '-aspect', f'{framecount}:{height}', outname
        ]
        ffmpeg_cmd(cmd,
                   length,
                   stream=False,
                   pb_prefix="Rendering horizontal videogram:")

        outname = self.of + '_vgx.png'
        cmd = [
            'ffmpeg', '-y', '-i', self.filename, '-frames', '1', '-vf',
            f'scale={width}:1:sws_flags=area,normalize,tile=1x{framecount}',
            '-aspect', f'{width}:{framecount}', outname
        ]
        ffmpeg_cmd(cmd,
                   length,
                   stream=False,
                   pb_prefix="Rendering vertical videogram:")

        return MgList(
            [MgImage(self.of + '_vgx.png'),
             MgImage(self.of + '_vgy.png')])