I'm trying to learn OpenCV by doing a few things on my own. In this particular case, I wanted to take the bit planes of a grayscale image. The code seems to have worked, but it only works well for the bit 7 and 6, not so much for the remaining 6, as it only shows a good result for about 1/3 of the image. I just haven't found what's wrong with it as of yet. I'd greatly appreciate some help on the matter, as I'm just doing my first codes with the libraries.
Here's what I get for the first bit:
And here is it for the 7th bit:
And here's my code:
#include <opencv2\opencv.hpp>
#include <math.h>
using namespace cv;
using namespace std;
int main( int argc, char** argv ) {
Mat m1 = imread("grayscalerose.jpg");
imshow("Original",m1);
int cols, rows, x, y;
cols = m1.cols;
rows = m1.rows;
printf("%d %d \n",m1.rows,m1.cols);
Mat out1(rows, cols, CV_8UC1, Scalar(0));
out1 = (m1/128); //Here's where I divide by either 1,2,4,8,16,32,64, or 128 to get the corresponding bit planes
for (int y = 0; y < rows; y++){
for (int x = 0; x < cols; x++){
out1.at<uchar>(y,x) = (out1.at<uchar>(y,x) % 2);
} }
out1 = out1*255;
imshow("out1",out1);
waitKey(0);
destroyWindow( "out1" );
}
Thanks in advance. I hope my explanation wasn't too messy.
A bit plane of a digital discrete signal (such as image or sound) is a set of bits corresponding to a given bit position in each of the binary numbers representing the signal.
Bit-plane encoding is intended for use aboard spacecraft. The technique presumes input data in binary form. The encoder implemen- tation consists of a memory to store datasamples, a monitor, and a code box. Both the monitor and the code box perform simple opera- tions on binary sequences.
Bit plane slicing is a method of representing an image with one or more bits of the byte used for each pixel. One can use only MSB to represent the pixel, which reduces the original gray level to a binary image. The three main goals of bit plane slicing is: Converting a gray level image to a binary image.
The highest bit-plane is the Most Significant Bit (MSB) and the lowest bit-plane is the Least Significant Bit (LSB). As such, each bit-plane descending from MSB to LSB makes a decaying, marginal contribution to the overall information contained in the image.
First let's read the image in as grayscale only. (As mentioned by user3896254).
Then, let's prepare a mask image, where only the least significant bit is set -- i.e. all the values are 1.
Then the algorithm is simple. Let's avoid per-pixel manipulation (the two nested for loops), and try to take advantage of the optimized operations provided by OpenCV.
For each bit (0..7):
Code:
#include <opencv2\opencv.hpp>
#include <cstdint>
int main(int argc, char** argv)
{
cv::Mat input_img(cv::imread("peppers.png", 0));
int32_t rows(input_img.rows), cols(input_img.cols);
cv::Mat bit_mask(cv::Mat::ones(rows, cols, CV_8UC1));
cv::Mat work_img(input_img.clone());
std::string file_name("peppers_bit0.png");
for (uint32_t i(0); i < 8; ++i) {
cv::Mat out;
cv::bitwise_and(work_img, bit_mask, out);
out *= 255;
cv::imwrite(file_name, out);
work_img = work_img / 2;
file_name[11] += 1;
}
}
We can develop even shorter (and probably faster) version using a single matrix expression.
We can calculate the appropriate divisor using the expression (1<<i)
. We divide every element by this value to shift the bits, mask each element by ANDing it with 1, and then scale all the elements by 255:
#include <opencv2\opencv.hpp>
#include <cstdint>
int main(int argc, char** argv)
{
cv::Mat input_img(cv::imread("peppers.png", 0));
std::string file_name("peppers_bit0.png");
for (uint32_t i(0); i < 8; ++i) {
cv::Mat out(((input_img / (1<<i)) & 1) * 255);
cv::imwrite(file_name, out);
file_name[11] += 1;
}
}
Input image:
Bit 0:
Bit 1:
Bit 2:
Bit 3:
Bit 4:
Bit 5:
Bit 6:
Bit 7:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With