Previous tutorial: Homemade linear filter
Next tutorial: Sobel edge detection operator
Original author | Ana Huamán |
---|---|
Compatibility | OpenCV >= 3.0 |
Goals
In this tutorial you will learn how to
- Use the OpenCV function copyMakeBorder() to set the border (extra padding for the image).
Principles
Comments
The following explanation comes from the book Learning OpenCV by Bradski and Kaehler.
-
In the previous tutorial, we learned about using convolutions to operate on images. A question that naturally arises is how to deal with boundaries. How do we convolve if the evaluation point is at the edge of the image?
-
What most OpenCV functions do is copy the given image onto another, slightly larger image, and then automatically fill in the boundaries (using any of the methods explained in the sample code below). This way, the convolution proceeds smoothly on the desired pixels (excess padding is clipped off after the operation is complete).
-
In this tutorial, we will briefly explore two methods of defining additional padding (border) for images:
a. BORDER_CONSTANT: Fills the image with a constant value (such as black or 0).
b. BORDER_REPLICATE: Copy rows or columns from the edge of the original image into an extra border.
The code section will illustrate this more clearly.
- What does this program do?
-
Load image
-
Let the user choose which padding to use in the input image. There are two options
- Constant value border: Applies a constant value padding to the entire border. The value is updated randomly every 0.5 seconds.
- Copy Border: The border will be copied based on the pixel values of the edges of the original image.
The user can press “c” (constant) or “r” (replicate) to select one of the options.
-
The program ends when the user presses the “ESC” key.
-
Code
C++
The tutorial code is shown below.
You can also download it from here
#include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" using namespace cv; // declare variables Mat src, dst; int top, bottom, left, right; int borderType = BORDER_CONSTANT; const char* window_name = "copyMakeBorder Demo"; RNG rng(12345); int main(int argc, char** argv) {<!-- --> const char* imageName = argc >=2 ? argv[1] : "lena.jpg"; //Load image src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load image // Check whether the image is loaded normally if( src.empty()) {<!-- --> printf("Error opening image\ "); printf("Program Arguments: [image_name -- default lena.jpg] \ "); return -1; } // Brief operation method of this program printf( "\ \t copyMakeBorder Demo: \ " ); printf( "\t -------------------- \ " ); printf( " ** Press 'c' to set the border to a random constant value \ "); printf( " ** Press 'r' to set the border to be replicated \ "); printf( " ** Press 'ESC' to exit the program \ "); namedWindow(window_name, WINDOW_AUTOSIZE); //Initialize filter parameters top = (int) (0.05*src.rows); bottom = top; left = (int) (0.05*src.cols); right = left; for(;;) {<!-- --> Scalar value( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) ); copyMakeBorder( src, dst, top, bottom, left, right, borderType, value ); imshow(window_name, dst); char c = (char)waitKey(500); if( c == 27 ) {<!-- --> break; } else if( c == 'c' ) {<!-- --> borderType = BORDER_CONSTANT; } else if( c == 'r' ) {<!-- --> borderType = BORDER_REPLICATE; } } return 0; }
Java
The tutorial code is shown below.
You can also download it from here
import org.opencv.core.*; import org.opencv.highgui.HighGui; import org.opencv.imgcodecs.Imgcodecs; import java.util.Random; class CopyMakeBorderRun {<!-- --> public void run(String[] args) {<!-- --> // declare variables Mat src, dst = new Mat(); int top, bottom, left, right; int borderType = Core.BORDER_CONSTANT; String window_name = "copyMakeBorder Demo"; Random rng; String imageName = ((args.length > 0) ? args[0] : "../data/lena.jpg"); //Load image src = Imgcodecs.imread(imageName, Imgcodecs.IMREAD_COLOR); // Check whether the image is loaded normally if( src.empty() ) {<!-- --> System.out.println("Error opening image!"); System.out.println("Program Arguments: [image_name -- default ../data/lena.jpg] \ "); System.exit(-1); } // A brief description of the program System.out.println("\ " + "\t copyMakeBorder Demo: \ " + "\t-------------------- \ " + " ** Press 'c' to set the border to a random constant value \ " + " ** Press 'r' to set the border to be replicated \ " + " ** Press 'ESC' to exit the program \ "); HighGui.namedWindow( window_name, HighGui.WINDOW_AUTOSIZE ); //Initialize filter parameters top = (int) (0.05*src.rows()); bottom = top; left = (int) (0.05*src.cols()); right = left; while( true ) {<!-- --> rng = new Random(); Scalar value = new Scalar( rng.nextInt(256), rng.nextInt(256), rng.nextInt(256) ); Core.copyMakeBorder(src, dst, top, bottom, left, right, borderType, value); HighGui.imshow(window_name, dst); char c = (char) HighGui.waitKey(500); c = Character.toLowerCase(c); if( c == 27 ) {<!-- --> break; } else if( c == 'c' ) {<!-- --> borderType = Core.BORDER_CONSTANT;} else if( c == 'r' ) {<!-- --> borderType = Core.BORDER_REPLICATE;} } System.exit(0); } } public class CopyMakeBorder {<!-- --> public static void main(String[] args) {<!-- --> //Load the local library. System.loadLibrary(Core.NATIVE_LIBRARY_NAME); new CopyMakeBorderRun().run(args); } }
Python
The tutorial code is shown below.
You can also download it from here
""" @file copy_make_border.py @brief Sample code that shows the functionality of copyMakeBorder """ importsys from random import randint import cv2 as cv def main(argv): borderType = cv.BORDER_CONSTANT window_name = "copyMakeBorder Demo" imageName = argv[0] if len(argv) > 0 else 'lena.jpg' #Load image src = cv.imread(cv.samples.findFile(imageName), cv.IMREAD_COLOR) # Check whether the image is loaded normally if src is None: print ('Error opening image!') print ('Usage: copy_make_border.py [image_name -- default lena.jpg] \ ') return -1 print ('\ ' '\t copyMakeBorder Demo: \ ' '--------------------\ ' ' ** Press 'c' to set the border to a random constant value \ ' ' ** Press 'r' to set the border to be replicated \ ' ' ** Press 'ESC' to exit the program ') cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE) top = int(0.05 * src.shape[0]) # shape[0] = rows bottom = top left = int(0.05 * src.shape[1]) # shape[1] = cols right = left while 1: value = [randint(0, 255), randint(0, 255), randint(0, 255)] dst = cv.copyMakeBorder(src, top, bottom, left, right, borderType, None, value) cv.imshow(window_name, dst) c = cv.waitKey(500) if c == 27: break elif c == 99: # 99 = ord('c') borderType = cv.BORDER_CONSTANT elif c == 114: # 114 = ord('r') borderType = cv.BORDER_REPLICATE return 0 if __name__ == "__main__": main(sys.argv[1:])
Description
Declare variables
First, we declare the variables we will use:
C++
// Declare the variables Mat src, dst; int top, bottom, left, right; int borderType = BORDER_CONSTANT; const char* window_name = "copyMakeBorder Demo"; RNG rng(12345);
Java
// Declare the variables Mat src, dst = new Mat(); int top, bottom, left, right; int borderType = Core.BORDER_CONSTANT; String window_name = "copyMakeBorder Demo"; Random rng;
Python
# First we declare the variables we are going to use borderType = cv.BORDER_CONSTANT window_name = "copyMakeBorder Demo"
Of particular note is the variable rng, which is a random number generator. We use this to generate random border colors, as you’ll see shortly.
Load images
As usual, we load the source image src:
C++
const char* imageName = argc >=2 ? argv[1] : "lena.jpg"; // Loads an image src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image // Check if image is loaded fine if( src.empty()) {<!-- --> printf("Error opening image\ "); printf("Program Arguments: [image_name -- default lena.jpg] \ "); return -1; }
Java
String imageName = ((args.length > 0) ? args[0] : "../data/lena.jpg"); // Load an image src = Imgcodecs.imread(imageName, Imgcodecs.IMREAD_COLOR); // Check if image is loaded fine if( src.empty() ) {<!-- --> System.out.println("Error opening image!"); System.out.println("Program Arguments: [image_name -- default ../data/lena.jpg] \ "); System.exit(-1); }
Python
imageName = argv[0] if len(argv) > 0 else 'lena.jpg' #Loads an image src = cv.imread(cv.samples.findFile(imageName), cv.IMREAD_COLOR) # Check if image is loaded fine if src is None: print ('Error opening image!') print ('Usage: copy_make_border.py [image_name -- default lena.jpg] \ ') return -1
Create window
After a brief introduction on how to use the program, we create a window:
C++
namedWindow( window_name, WINDOW_AUTOSIZE );
Java
HighGui.namedWindow( window_name, HighGui.WINDOW_AUTOSIZE );
Python
cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE)
Initialization parameters
Now we initialize the parameters that define the border size (top, bottom, left and right). The value we give them is 5% of the size of src.
C++
// Initialize arguments for the filter top = (int) (0.05*src.rows); bottom = top; left = (int) (0.05*src.cols); right = left;
Java
// Initialize arguments for the filter top = (int) (0.05*src.rows()); bottom = top; left = (int) (0.05*src.cols()); right = left;
Python
# Initialize arguments for the filter top = int(0.05 * src.shape[0]) # shape[0] = rows bottom = top left = int(0.05 * src.shape[1]) # shape[1] = cols right = left
Loop
If the ESC key is not pressed, the program will run in an infinite loop. If the user presses the “c” or “r” key, the value of the borderType variable is BORDER_CONSTANT or BORDER_REPLICATE respectively:
C++
char c = (char)waitKey(500); if( c == 27 ) {<!-- --> break; } else if( c == 'c' ) {<!-- --> borderType = BORDER_CONSTANT; } else if( c == 'r' ) {<!-- --> borderType = BORDER_REPLICATE; }
Java
char c = (char) HighGui.waitKey(500); c = Character.toLowerCase(c); if( c == 27 ) {<!-- --> break; } else if( c == 'c' ) {<!-- --> borderType = Core.BORDER_CONSTANT;} else if( c == 'r' ) {<!-- --> borderType = Core.BORDER_REPLICATE;}
Python
c = cv.waitKey(500) if c == 27: break elif c == 99: # 99 = ord('c') borderType = cv.BORDER_CONSTANT elif c == 114: # 114 = ord('r') borderType = cv.BORDER_REPLICATE
Random Color
Every iteration (after 0.5 seconds) the random border color (value) is updated…
C++
Scalar value( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );
Java
rng = new Random(); Scalar value = new Scalar( rng.nextInt(256), rng.nextInt(256), rng.nextInt(256) );
Python
value = [randint(0, 255), randint(0, 255), randint(0, 255)]
The value is a set of three randomly chosen numbers in the range [0,255].
Form a border around the image
Finally, we call the copyMakeBorder() function to apply the appropriate padding:
C++
copyMakeBorder( src, dst, top, bottom, left, right, borderType, value );
Java
Core.copyMakeBorder(src, dst, top, bottom, left, right, borderType, value);
Python
dst = cv.copyMakeBorder(src, top, bottom, left, right, borderType, None, value)
- The parameters are as follows
- src: source image
- dst: target image
- top, bottom, left, right: The length of the borders on both sides of the image (in pixels). We define this as 5% of the original size of the image.
- borderType: Border type: Defines the applied border type. Constants or copying can be used in this example.
- value: If borderType is BORDER_CONSTANT, this value is used to fill the border pixels.
Show results
We display the output image in the image we created earlier
C++
imshow(window_name, dst);
Java
HighGui.imshow( window_name, dst );
Python
cv.imshow(window_name, dst)
Results
-
After compiling the above code, it can be executed with the image path as a parameter. The result should be
- By default, the border is set to BORDER_CONSTANT initially. Therefore, a range of randomly colored borders will be displayed.
- If you press the “r” key, the border will become a copy of the edge pixels.
- If you press the “c” key, a random colored border will appear again.
- If you press the “ESC” key, the program will exit.
The screenshot below shows the color change of the border and the effect of the BORDER_REPLICATE option: