def debug_image(block_size, frame_base, list_predictive, list_residuals, output_location): """ Note: I haven't made an effort to maintain this method, as it's only for debugging. This section can best be explained through pictures. A visual way of expressing what 'debug' is doing is this section in the wiki. https://github.com/aka-katto/dandere2x/wiki/How-Dandere2x-Works#part-1-identifying-what-needs-to-be-drawn In other words, this method shows where residuals are, and is useful for finding good settings to use for a video. Inputs: - frame(x) - Residual vectors mapping frame(x)_residual -> frame(x) Output: - frame(x) minus frame(x)_residuals = debug_image """ logger = logging.getLogger(__name__) difference_vectors = [] predictive_vectors = [] out_image = Frame() out_image.create_new(frame_base.width, frame_base.height) out_image.copy_image(frame_base) black_image = Frame() black_image.create_new(frame_base.width, frame_base.height) if not list_predictive and not list_residuals: out_image.save_image(output_location) return if list_predictive and not list_residuals: out_image.copy_image(frame_base) out_image.save_image(output_location) return # load list into vector displacements for x in range(int(len(list_residuals) / 4)): difference_vectors.append(DisplacementVector(int(list_residuals[x * 4]), int(list_residuals[x * 4 + 1]), int(list_residuals[x * 4 + 2]), int(list_residuals[x * 4 + 3]))) for x in range(int(len(list_predictive) / 4)): if (int(list_predictive[x * 4 + 0]) != int(list_predictive[x * 4 + 1])) and \ (int(list_predictive[x * 4 + 2]) != int(list_predictive[x * 4 + 3])): predictive_vectors.append(DisplacementVector(int(list_predictive[x * 4 + 0]), int(list_predictive[x * 4 + 1]), int(list_predictive[x * 4 + 2]), int(list_predictive[x * 4 + 3]))) # copy over predictive vectors into new image for vector in difference_vectors: out_image.copy_block(black_image, block_size, vector.x_1, vector.y_1, vector.x_1, vector.y_1) out_image.save_image(output_location)
def pframe_image(context: Dandere2xServiceContext, frame_next: Frame, frame_previous: Frame, frame_residual: Frame, list_residual: list, list_predictive: list): """ Create a new image using residuals and predictive vectors. Roughly, we can describe this method as frame_next = Transfrom(frame_previous, list_predictive) + frame_residuals. Although frame_residuals needs to also be transformed. Method Tasks: - Move blocks from frame_previous into frame_next using list_predictive - Move blocks from frame_residual into frame_next using list_residuals """ # load context scale_factor = int(context.service_request.scale_factor) block_size = context.service_request.block_size bleed = context.bleed for x in range(int(len(list_predictive) / 4)): """ Neat optimization trick - there's no need for pframe to copy over a block if the vectors point to the same place. In merge.py we just need to load the previous frame into the current frame to reach this optimization. """ if int(list_predictive[x * 4 + 0]) != int(list_predictive[x * 4 + 1]) \ or \ int(list_predictive[x * 4 + 2]) != int(list_predictive[x * 4 + 3]): # load the vector vector = DisplacementVector(int(list_predictive[x * 4 + 0]), int(list_predictive[x * 4 + 1]), int(list_predictive[x * 4 + 2]), int(list_predictive[x * 4 + 3])) # apply the vector frame_next.copy_block(frame_previous, block_size * scale_factor, vector.x_2 * scale_factor, vector.y_2 * scale_factor, vector.x_1 * scale_factor, vector.y_1 * scale_factor) for x in range(int(len(list_residual) / 4)): # load every element in the list into a vector vector = DisplacementVector(int(list_residual[x * 4 + 0]), int(list_residual[x * 4 + 1]), int(list_residual[x * 4 + 2]), int(list_residual[x * 4 + 3])) # apply that vector to the image frame_next.copy_block(frame_residual, block_size * scale_factor, (vector.x_2 * (block_size + bleed * 2)) * scale_factor + (bleed * scale_factor), (vector.y_2 * (block_size + bleed * 2)) * scale_factor + (bleed * scale_factor), vector.x_1 * scale_factor, vector.y_1 * scale_factor) return frame_next
def make_residual_image(context: Dandere2xServiceContext, raw_frame: Frame, list_residual: list, list_predictive: list): """ This section can best be explained through pictures. A visual way of expressing what 'make_residual_image' is doing is this section in the wiki. https://github.com/aka-katto/dandere2x/wiki/How-Dandere2x-Works#observation_3 Inputs: - frame(x) - Residual vectors mapping frame(x)_residual -> frame(x) Output: - frame(x)_residual """ # Some conditions to check before making a residual image, in both cases, we don't need to do any actual # processing in the function call, if these conditions hold true. if not list_residual and list_predictive: """ If there are no items in 'list_residuals' but have list_predictives then the two frames are identical, so no residual image needed. """ residual_image = Frame() residual_image.create_new(1, 1) return residual_image if not list_residual and not list_predictive: """ If there are neither any predictive or inversions, then the frame is a brand new frame with no resemblence to previous frame. In this case, copy the entire frame over. """ residual_image = Frame() residual_image.create_new(raw_frame.width, raw_frame.height) residual_image.copy_image(raw_frame) return residual_image buffer = 5 block_size = context.service_request.block_size bleed = context.bleed """ First make a 'bleeded' version of input_frame, as we need to create a buffer in the event the 'bleed' ends up going out of bounds. In other words, crop the image into an even larger image, so that if if we need to access out of bounds pixels, and place black pixels where it would be out of bounds. """ bleed_frame = raw_frame.create_bleeded_image(buffer) # size of output image is determined based off how many residuals there are image_size = int(math.sqrt(len(list_residual) / 4) + 1) * (block_size + bleed * 2) residual_image = Frame() residual_image.create_new(image_size, image_size) for x in range(int(len(list_residual) / 4)): # load every element in the list into a vector vector = DisplacementVector(int(list_residual[x * 4 + 0]), int(list_residual[x * 4 + 1]), int(list_residual[x * 4 + 2]), int(list_residual[x * 4 + 3])) # apply that vector to the image by copying over their respective blocks. residual_image.copy_block(bleed_frame, block_size + bleed * 2, vector.x_1 + buffer - bleed, vector.y_1 + buffer + - bleed, vector.x_2 * (block_size + bleed * 2), vector.y_2 * (block_size + bleed * 2)) return residual_image