def generate_sliding_windows(window_shape, window_strides, image_shape):
    """Generate sliding windows

    Args:
        window_shape (2-tuple): (h, w)
        window_strides (2-tuple): (sy, sx)
        image_shape (2-tuple): (H, W)

    Returns:
        boxes (list of list): (N, 4), where N = (H-h+1)//sy * (W-w+1)/sx;
            boxes in image
        indices (list of list): (N, h*w)
            flatten coordinates in image
        num_cells (tuple): number of cells in y-axis and x-axis

    """
    h, w = window_shape
    sy, sx = window_strides
    H, W = image_shape

    ys_start = list(range(0, H - h + 1, sy))
    xs_start = list(range(0, W - w + 1, sx))

    boxes = []
    indices = []
    num_cells = (len(ys_start), len(xs_start))
    for y_start in ys_start:
        for x_start in xs_start:
            index = []
            for y in range(y_start, y_start + h):
                for x in range(x_start, x_start + w):
                    index.append(y * W + x)
            boxes.append([x_start, y_start, w, h])
            indices.append(index)
    return boxes, indices, num_cells