diy:projets:chromakey
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| diy:projets:chromakey [2018/06/25 09:04] – [Sources du projet] sdurand | diy:projets:chromakey [2018/07/02 09:35] (Version actuelle) – [Sources du projet] sdurand | ||
|---|---|---|---|
| Ligne 314: | Ligne 314: | ||
| === " | === " | ||
| - | #include < | + | <code C++> |
| - | | + | #include < |
| - | | + | #include < |
| - | | + | #include < |
| - | + | #include < | |
| - | + | ||
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | + | ||
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | + | ||
| - | + | ||
| - | // For a bit of comfort | + | |
| - | using namespace cv; | + | |
| - | + | ||
| - | // Simple function to test if a channel of a pixel (B, G or R) is within the interval [value - offset; value + offset] | + | |
| - | | + | |
| - | | + | |
| - | } | + | |
| - | + | ||
| - | + | ||
| - | // Most important part of the code: | + | |
| - | // Replaces the pixels of the frame close enough (depending of the offset) to the color B, G, R | + | |
| - | | + | |
| - | // Using openMP was definitely worth on a Raspberry Pi 3 model B | + | |
| - | # | + | |
| - | // Iterating on the rows of our frame | + | |
| - | | + | |
| - | // Using a pointer to the rows is the fastest way to access a matrix | + | |
| - | Vec3b *Fi = frame.ptr< | + | |
| - | const Vec3b *Bi = background.ptr< | + | |
| - | + | ||
| - | // Iterating on the elements of each row | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | } | + | |
| - | } | + | |
| - | } | + | |
| - | } | + | |
| - | } | + | |
| - | + | ||
| - | + | ||
| - | int main(int argc, char** argv) { | + | |
| - | // Just a simple parameters check | + | |
| - | | + | |
| - | | + | |
| - | + | ||
| - | | + | |
| - | } | + | |
| - | + | ||
| - | // This Mat contains our background | + | |
| - | Mat background; | + | |
| - | | + | |
| - | + | ||
| - | // Testing that the images size is the same as defined | + | |
| - | // We could also just reshape the image, it would be a bit less restrictive | + | |
| - | | + | |
| - | | + | |
| - | + | ||
| - | | + | |
| - | } | + | |
| - | + | ||
| - | int B, G, R, offset; | + | |
| - | + | ||
| - | // Getting the parameters from the command line | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | + | ||
| - | rb >> B; | + | |
| - | rg >> G; | + | |
| - | rr >> R; | + | |
| - | rt >> offset; | + | |
| - | + | ||
| - | // This Mat will contain the images | + | |
| - | Mat frame; | + | |
| - | // Initializing the capture, should be equivalent to: | + | |
| - | // VideoCapture cam(0); | + | #define WIDTH 1280 |
| - | VideoCapture cam(0); | + | #define HEIGHT 720 |
| - | | + | #define FRAME_SIZE WIDTH*HEIGHT*3 |
| - | // Setting the width and height of the capture as defined | + | #define NUMBER_OF_FRAMES 150 |
| - | // If not set, default resolution is 640*480 | + | |
| - | cam.set(3, WIDTH); | + | #define ALL_GOOD 0 |
| - | cam.set(4, HEIGHT); | + | #define INVALID_ARGUMENTS -1 |
| - | | + | #define INVALID_IMAGE -2 |
| - | // Adding the OpenCV JPEG parameters to a vector, this is used to encode a Mat with non-default settings | + | |
| - | std:: | + | |
| - | jpg_parameters.push_back(CV_IMWRITE_JPEG_QUALITY); | + | // For a bit of comfort |
| - | jpg_parameters.push_back(75); | + | using namespace cv; |
| - | | + | |
| - | std:: | + | // Simple function to test if a channel of a pixel (B, G or R) is within the interval [value - offset; value + offset] |
| - | | + | inline bool inBounds(int value, int bound, int offset) { |
| - | | + | return abs(value - bound) <= offset; |
| - | const auto start = std:: | + | } |
| - | | + | |
| - | do { | + | |
| - | cam >> frame; | + | // Most important part of the code: |
| - | } while(frame.empty()); | + | // Replaces the pixels of the frame close enough (depending of the offset) to the color B, G, R |
| - | | + | inline void chromakey(Mat& |
| - | chromakey(frame, | + | // Using openMP was definitely worth on a Raspberry Pi 3 model B |
| - | | + | #pragma omp parallel for |
| - | // Encoding the frame | + | // Iterating on the rows of our frame |
| - | imencode(" | + | for(int i = 0; i < frame.rows; i++) { |
| - | const unsigned int size = buffer.size(); | + | // Using a pointer to the rows is the fastest way to access a matrix |
| - | | + | Vec3b *Fi = frame.ptr< |
| - | // Writing the encoded image to stdout | + | const Vec3b *Bi = background.ptr< |
| - | // unsigned int and uchar size are the same on ARM and 64 bits regular computer | + | |
| - | fwrite(& | + | // Iterating on the elements of each row |
| - | fwrite(buffer.data(), | + | for(int j = 0; j < frame.cols; j++) { |
| - | | + | // If the pixel (i, j) of our frame is close enough to B, G and R, we replace it with the color of the background (i, j) pixel |
| - | // We use stderr to print an FPS counter and not because we are already writing images on stdout | + | if(inBounds(Fi[j][0], |
| - | const std:: | + | for(int k = 0; k < 3; k++) { |
| - | | + | Fi[j][k] = Bi[j][k]; |
| - | std::cerr << " | + | } |
| - | } | + | } |
| - | std::cerr << std:: | + | } |
| - | | + | } |
| - | return ALL_GOOD; | + | } |
| - | | + | |
| + | |||
| + | int main(int argc, char** argv) { | ||
| + | // Just a simple parameters check | ||
| + | if(argc != 6) { | ||
| + | std::cerr << " | ||
| + | |||
| + | return INVALID_ARGUMENTS; | ||
| + | } | ||
| + | |||
| + | // This Mat contains our background | ||
| + | Mat background; | ||
| + | background = imread(argv[5]); | ||
| + | |||
| + | // Testing that the images size is the same as defined | ||
| + | // We could also just reshape the image, it would be a bit less restrictive | ||
| + | if(!background.data || background.cols != WIDTH || background.rows != HEIGHT) { | ||
| + | std::cerr << " | ||
| + | |||
| + | return INVALID_IMAGE; | ||
| + | } | ||
| + | |||
| + | int B, G, R, offset; | ||
| + | |||
| + | // Getting the parameters from the command line | ||
| + | std:: | ||
| + | std:: | ||
| + | std:: | ||
| + | std:: | ||
| + | |||
| + | rb >> B; | ||
| + | rg >> G; | ||
| + | rr >> R; | ||
| + | rt >> offset; | ||
| + | |||
| + | // This Mat will contain the images | ||
| + | Mat frame; | ||
| + | |||
| + | // Initializing the capture, should be equivalent to: | ||
| + | // VideoCapture cam(0); | ||
| + | VideoCapture cam(0); | ||
| + | |||
| + | // Setting the width and height of the capture as defined | ||
| + | // If not set, default resolution is 640*480 | ||
| + | cam.set(3, WIDTH); | ||
| + | cam.set(4, HEIGHT); | ||
| + | |||
| + | // Adding the OpenCV JPEG parameters to a vector, this is used to encode a Mat with non-default settings | ||
| + | std:: | ||
| + | jpg_parameters.push_back(CV_IMWRITE_JPEG_QUALITY); | ||
| + | jpg_parameters.push_back(75); | ||
| + | |||
| + | std:: | ||
| + | |||
| + | for(int frame_count = 0; frame_count < NUMBER_OF_FRAMES; | ||
| + | const auto start = std:: | ||
| + | |||
| + | do { | ||
| + | cam >> frame; | ||
| + | } while(frame.empty()); | ||
| + | |||
| + | chromakey(frame, | ||
| + | |||
| + | // Encoding the frame | ||
| + | imencode(" | ||
| + | const unsigned int size = buffer.size(); | ||
| + | |||
| + | // Writing the encoded image to stdout | ||
| + | // unsigned int and uchar size are the same on ARM and 64 bits regular computer | ||
| + | fwrite(& | ||
| + | fwrite(buffer.data(), | ||
| + | |||
| + | // We use stderr to print an FPS counter and not because we are already writing images on stdout | ||
| + | const std:: | ||
| + | |||
| + | std::cerr << " | ||
| + | } | ||
| + | std::cerr << std:: | ||
| + | |||
| + | return ALL_GOOD; | ||
| + | } | ||
| + | </ | ||
| === " | === " | ||
| + | <code C++> | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // WIDTH, HEIGHT and NUMBER_OF_FRAMES should always be set to the same value as in the transmitter | ||
| + | #define WIDTH 1280 | ||
| + | #define HEIGHT 720 | ||
| + | // Maximum size of the received frame | ||
| + | // In theory, if jpeg doesn' | ||
| + | // I'm not sure it can ever happen, so, as this program should not be used for critical stuff (it really should not), I'm just gonna assume it won't happen | ||
| + | #define FRAME_SIZE WIDTH*HEIGHT*3 | ||
| + | #define NUMBER_OF_FRAMES 150 | ||
| + | |||
| + | #define ALL_GOOD 0 | ||
| + | |||
| + | |||
| + | |||
| + | int main(int argc, char **argv) { | ||
| + | // Actual size of the received frame | ||
| + | unsigned int size; | ||
| + | uchar buffer[FRAME_SIZE]; | ||
| + | cv::Mat frame; | ||
| + | |||
| + | for(int frame_count = 0; frame_count < NUMBER_OF_FRAMES; | ||
| + | // Reading the encoded image from stdin | ||
| + | // unsigned int and uchar size are the same on ARM and 64 bits regular computer | ||
| + | fread(& | ||
| + | fread(buffer, | ||
| + | |||
| + | std:: | ||
| + | |||
| + | // Decoding the received frame | ||
| + | frame = cv:: | ||
| + | |||
| + | // Displaying the received frame | ||
| + | cv:: | ||
| + | |||
| + | // This wait is mandatory for the image to actually display | ||
| + | cv:: | ||
| + | } | ||
| + | |||
| + | return ALL_GOOD; | ||
| + | } | ||
| + | </ | ||
| ---- | ---- | ||
| - | // | + | // |
diy/projets/chromakey.1529917485.txt.gz · Dernière modification : de sdurand
