OpenCV中1平面图像的位平面仅适用于图像的1/3

D. *_*anz 6 c++ opencv image-processing

我正在尝试通过自己做一些事来学习OpenCV.在这种特殊情况下,我想拍摄灰度图像的位平面.代码似乎有效,但它只适用于第7位和第6位,而不是其余6位,因为它只显示约1/3图像的良好结果.我还没有发现它有什么问题.我非常感谢有关此问题的一些帮助,因为我只是在编写我的第一个代码库.

这是我得到的第一位:

在此输入图像描述

这是第7位:

在此输入图像描述

这是我的代码:

#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" );

}
Run Code Online (Sandbox Code Playgroud)

提前致谢.我希望我的解释不是太乱.

Dan*_*šek 5

首先让我们仅以灰度读取图像。(如user3896254 所述)。

然后,让我们准备一个掩码图像,其中只设置最低有效位——即所有值都是 1。

那么算法就简单了。让我们避免逐像素操作(两个嵌套的 for 循环),并尝试利用 OpenCV 提供的优化操作。

对于每一位(0..7):

  • 屏蔽工作图像中的最低位。
  • 将蒙版图像缩放 255 以使其成为黑色/白色。
  • 存储输出。
  • 将工作图像中的值除以 2 - 即将所有位向右移动 1 个位置。

代码:

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们可以使用单个矩阵表达式开发更短(可能更快)的版本。

我们可以使用表达式计算适当的除数(1<<i)。我们将每个元素除以这个值以移动位,通过与 1 进行 AND 运算来屏蔽每个元素,然后将所有元素缩放 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

样品运行

输入图像:

位 0:

位 1:

位 2:

位 3:

位 4:

位 5:

位 6:

位 7:


Mik*_*iki 3

当您将15( 0x00001111)除以2( 0x00000010) 时,您会得到7( 0x00000111),这不是您所期望的。您可以检查某个位是否已设置,如:15 & 2,如果未设置第二位,则生成 0,否则生成大于 0 的值。这同样适用于其他值。

尝试以下代码。注意:

  • 您需要将图像加载为灰度(使用IMREAD_GRAYSCALEin imread
  • 您可以直接输入值0,也可以255在选择位时输入值

代码:

#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat m1 = imread("path_to_image", IMREAD_GRAYSCALE);
    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));


    for (int y = 0; y < rows; y++){
        for (int x = 0; x < cols; x++){
            out1.at<uchar>(y, x) = (m1.at<uchar>(y, x) & uchar(64)) ? uchar(255) : uchar(0); //Here's where I AND by either 1,2,4,8,16,32,64, or 128 to get the corresponding bit planes
        }
    }

    imshow("out1", out1);
    waitKey(0);
    destroyWindow("out1");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)