Pythonizing C++ block with goto statement

Viewed 179

I have been Pythonising a C++ code and I came across a situation in which I kinda got stuck. The programmer used goto statements to implement his logic, and since there is no goto statement in Python and since I'd rather not to delve into funny goto implementations of it, I was wondering if we could somehow Pythonize the following block:

// Loop over all detected circles of the input image
    for (int j = 0; j < circle_radius_vec.size(); ++j)
    {   
        Jump: 

        // Variables for ROI
        int roi_height_width = 0;
        int roi_corner_x = 0;
        int roi_corner_y = 0;

        Point center_now(roi_height_width/2, roi_height_width/2);

        // Load aktuellen center point
        center_now = center_vec[j];

        // Calculate ROI 
        roi_height_width = circle_radius_vec[j];
        roi_corner_x = center_now.x - roi_height_width/2;
        roi_corner_y = center_now.y - roi_height_width/2;   

        // If ROI is outside of image skip circle
        if(roi_corner_x < 0){j++; goto Jump;}
        if(roi_corner_y < 0){j++; goto Jump;}
        if((roi_corner_x+roi_height_width) > input_img.cols){j++; goto Jump;}
        if((roi_corner_y+roi_height_width) > input_img.rows){j++; goto Jump;}

        // Create ROI from input image
        Rect roi = Rect(roi_corner_x, roi_corner_y, roi_height_width, roi_height_width);
        Mat img_roi = input_img(roi);

        // Create HSV representation of ROI
        Mat hsv;
        cvtColor(img_roi, hsv, COLOR_BGR2HSV);
        ...

He has the label called "Jump" to which he goes to. How could we Pythonize this one? Since we are already in a for loop, I am a bit hesistant to introduce more loops.

Thanks in advance.

EDIT: Thanks to the contributors, the following was suggested, however this gets stuck in an infinite loop:

# Loop over all detected circles of the input image
    for j in range(len(center_vec)):
        while True:
            # arrange the ROI
            # load the current center point
            center_now = center_vec[j] # take the center of ROI as the center of circle
            roi_height_width = int(round(circle_radius_vec[j])) # take the radius as height and width of the ROI
            roi_height_width = int(round(circle_radius_vec[j]))

            roi_corner_x = int(round(center_now[0] - roi_height_width / 2))
            roi_corner_y = int(round(center_now[1] - roi_height_width / 2))

            # If ROI is outside of image skip circle
            if roi_corner_x < 0:
                j += 1
                continue
            if roi_corner_y < 0:
                j += 1
                continue
            if roi_corner_x + roi_height_width > img.shape[1]:
                j += 1
                continue
            if roi_corner_y + roi_height_width > img.shape[0]:
                j += 1
                continue

        # create ROI from input image Rect
        roi = img[roi_corner_y:roi_corner_y+roi_height_width, roi_corner_x:roi_corner_x+roi_height_width]

        # Create HSV representation of ROI
        hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
3 Answers

The C++ code needs rework: the goto statement and index increase is equivalent to a continue instruction (you almost never need goto in a C/C++ program, and definitely not here, the original C++ code which is "emulating" continue because the author didn't know that it existed):

for (int j = 0; j < circle_radius_vec.size(); ++j)
    {   
        ..
        // If ROI is outside of image skip circle
        if(roi_corner_x < 0){continue;}

Note that now you don't need to increase manually the index, as continue skips to the next iteration, calling the ++j of your loop.

(the other issue of the incrementation+goto is that if the special case happens at the end of the array, then you can read outside the bounds of the array: undefined behaviour)

Now, you can transpose that directly in python: you have 2 options:

Either you go with indices (like your C++ code does)

for index in range(size):        
    ...
    if some_condition:
        continue

or just iterate on elements (more pythonic, because it doesn't use indices):

for a in the_list:
    # a is the current element of the list, not the index
    ...
    if some_condition:
        continue

In both cases, the for loop controls the iteration. You just tell python to skip to the next iteration with continue, just like in the "new" C++ code.

Since all the jumps seem to be preceeded by j++ and jump is the start of the loop, it would seem that the Python continue statement would solve your problem quite easily?

# Loop over all detected circles of the input image
for in range(1, circle_radius_vec.size()):

    # Variables for ROI
    roi_height_width = 0
    roi_corner_x = 0
    roi_corner_y = 0

    Point center_now(roi_height_width/2, roi_height_width/2)

    # Load aktuellen center point
    center_now = center_vec[j]

    # Calculate ROI 
    roi_height_width = circle_radius_vec[j]
    roi_corner_x = center_now.x - roi_height_width/2
    roi_corner_y = center_now.y - roi_height_width/2   

    # If ROI is outside of image skip circle
    if roi_corner_x < 0 or roi_corner_y < 0 or roi_corner_x + roi_height_width > input_img.cols or roi_corner_y + roi_height_width > input_img.rows:
        continue

    # Create ROI from input image
    Rect roi = Rect(roi_corner_x, roi_corner_y, roi_height_width, roi_height_width)
    img_roi = input_img(roi)

    # Create HSV representation of ROI
    hsv()
    cvtColor(img_roi, hsv, COLOR_BGR2HSV)
    ...

I would personally just invert the if statement and execute the bottom half of the code conditionally as follows:

# Loop over all detected circles of the input image
for in range(1, circle_radius_vec.size()):

    # Variables for ROI
    roi_height_width = 0
    roi_corner_x = 0
    roi_corner_y = 0

    Point center_now(roi_height_width/2, roi_height_width/2)

    # Load aktuellen center point
    center_now = center_vec[j]

    # Calculate ROI 
    roi_height_width = circle_radius_vec[j]
    roi_corner_x = center_now.x - roi_height_width/2
    roi_corner_y = center_now.y - roi_height_width/2   

    # If ROI is outside of image skip circle
    if roi_corner_x >= 0 and roi_corner_y >= 0 and roi_corner_x + roi_height_width <= input_img.cols and roi_corner_y + roi_height_width <= input_img.rows:


        # Create ROI from input image
        Rect roi = Rect(roi_corner_x, roi_corner_y, roi_height_width, roi_height_width)
        img_roi = input_img(roi)

        # Create HSV representation of ROI
        hsv()
        cvtColor(img_roi, hsv, COLOR_BGR2HSV)
        ...

Sure. I'd suggest this.

# Loop over all detected circles ot the input image.
for j in range(len(circle_radius_vec)):
    # Variables for ROI.
    roi_height_width = 0
    roi_corner_x = 0
    roi_corner_y = 0

    # Calculate ROI 
    roi_height_width = circle_radius_vec[j]
    roi_corner_x = center_now.x - roi_height_width/2
    roi_corner_y = center_now.y - roi_height_width/2

    center_now = Point(roi_height_width/2, roi_height_width/2)

    # Load aktuellen center point.
    center_now = center_vec[j]

    # Calculate ROI.
    if roi_corner_x < 0:
        continue
    if roi_corner_y < 0:
        continue
    if roi_corner_x + roi_height_width > input_img.cols:
        continue


    # Create ROI from input image.
    roi = Rect(roi_corner_x, roi_corner_y, roi_height_width, roi_height_width)
    img_roi = input_img(roi)

    # Create HSV representation of ROI.
    hsv = None
    cvtColor(img_roi, hsv, COLOR_BGR2HSV)

Since I don't know the rest of the code I can't be much accurate. Please, tell me if any error occurs.

Related