c++ Sobel过滤器不能水平过滤

cnh2zyt3  于 2023-03-20  发布在  其他
关注(0)|答案(1)|浏览(120)

基本上我的问题是我应用索贝尔过滤器到BMP图像,其中1像素是1位。但它没有做任何事情的图像,而过滤水平。
Sobel函数:

void sobelFilter(unsigned char** image, int width, int height) {
    const int vertical_kernel[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1} };
    const int horizontal_kernel[3][3] = { {1, 2, 1}, {0, 0, 0}, {-1, -2, -1} };
    unsigned char** outputX = new unsigned char* [height];
    for (int i = 0; i < height; i++) {
        outputX[i] = new unsigned char[width];
    }
    unsigned char** outputY = new unsigned char* [height];
    for (int i = 0; i < height; i++) {
        outputY[i] = new unsigned char[width];
    }
    unsigned char** filteredImage = new unsigned char* [height];
    for (int i = 0; i < height; i++) {
        filteredImage[i] = new unsigned char[width];
    }
    int Gx, Gy, G;
    for (int y = 1; y < height - 1; ++y) {
        for (int x = 1; x < width - 1; ++x) {
            Gx = image[y - 1][x + 1] + 2 * image[y][x + 1] + image[y + 1][x + 1]
                - image[y - 1][x - 1] - 2 * image[y][x - 1] - image[y + 1][x - 1];
            Gy = image[y + 1][x - 1] + 2 * image[y + 1][x] + image[y + 1][x + 1]
                - image[y - 1][x - 1] - 2 * image[y - 1][x] - image[y - 1][x + 1];
            G = abs(Gx) + abs(Gy);
            G = min(max(G, 0), 255);
            outputY[y][x] = abs(Gy);
            outputX[y][x] = Gx;
            filteredImage[y][x] = G;
        }
    }
    writeDataToFile(outputY, width, height, (char*)"differentialY.bmp");
    writeDataToFile(outputX, width, height, (char*)"differentialX.bmp");
    writeDataToFile(filteredImage, width, height, (char*)"differential.bmp");
}

接下来是我的代码。
我的代码:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
using namespace std;

void readHeaderOfAnImage(char* header, int headerSize, char* fileName) {
    ifstream fin(fileName, ios::binary);
    fin.read(header, headerSize);
    fin.close();
}

void readFileData(unsigned char** imageData, int width, int height, int headerSize, char* fileName) {
    ifstream fin(fileName, ios::binary);
    fin.ignore(headerSize);
    int padding = 4 - ((width / 8) % 4);
    unsigned char buffer = fin.get();
    for (int i = 0, counter = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            imageData[i][j] = buffer & (128 >> counter);
            ++counter;
            if (counter == 8) {
                buffer = fin.get();
                counter = 0;
            }
        }
        for (int k = 0; k < padding; ++k) fin.get();
    }
    fin.close();
}

void writeHeaderOfAnImage(char* header, int headerSize, char* fileName) {
    ofstream fout(fileName, ios::binary);
    fout.write(header, headerSize);
    fout.close();
}

void writeDataToFile(unsigned char** imageData, int width, int height, char* fileName) {
    ofstream fout(fileName, ios::app | ios::binary);
    int padding = 4 - ((width / 8) % 4);
    unsigned char buffer = 0;
    for (int i = 0, counter = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (counter == 8) {//bit ended, need new one
                fout.put(buffer);
                counter = 0;
                buffer = 0;
            }
            if (imageData[i][j]) buffer = buffer | (1 << (7 - counter));//black pixel?
            counter++;
        }
        for (int k = 0; k < padding; k++) //need padding
            for (int m = 0; m < 8; m++) {
                if (counter == 8) {
                    fout.put(buffer);
                    counter = 0;
                    buffer = 0;
                }
                counter++;
            }
        if (counter == 8) {
            fout.put(buffer);
            counter = 0;
            buffer = 0;
        }
    }
    fout.close();
}

unsigned char findMedian(unsigned char arr[], int n) {
    sort(arr, arr + n);
    return arr[n / 2];
}

void medianFilter(unsigned char** imageData, unsigned char ** medianFilteredImageData, int width, int height) {
    const int kernel = 3;
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            unsigned char window[kernel * kernel];
            int k = 0;
            for (int x = i - kernel / 2; x <= i + kernel / 2; x++) {
                for (int y = j - kernel / 2; y <= j + kernel / 2; y++) {
                    if (x >= 0 && x < height && y >= 0 && y < width) {
                        window[k] = imageData[x][y];
                        k++;
                    }
                }
            }
            medianFilteredImageData[i][j] = findMedian(window, k);
        }
    }
}

int main() {
    const int width = 3000, height = 3000, headerSize = 62;
    char imageToReadFrom[256], imageToWriteInAfterMedian[256] = "median.bmp", imageToWriteInAfterDifferential[256] = "differential.bmp";
    cout << "Write the name of image that you want to read:\n";
    cin >> imageToReadFrom;
    char* header = new char[headerSize];
    unsigned char** imageData = new unsigned char* [height];
    for (int i = 0; i < height; i++) imageData[i] = new unsigned char[width];
    unsigned char** medianFilteredImageData = new unsigned char* [height];
    for (int i = 0; i < height; i++) medianFilteredImageData[i] = new unsigned char[width];
    readHeaderOfAnImage(header, headerSize, imageToReadFrom);
    readFileData(imageData, width, height, headerSize, imageToReadFrom);
    medianFilter(imageData, medianFilteredImageData, width, height);
    writeHeaderOfAnImage(header, headerSize, imageToWriteInAfterMedian);
    writeDataToFile(medianFilteredImageData, width, height, imageToWriteInAfterMedian);
    writeHeaderOfAnImage(header, headerSize, imageToWriteInAfterDifferential);
    writeHeaderOfAnImage(header, headerSize, (char*)"differentialY.bmp");
    writeHeaderOfAnImage(header, headerSize, (char*)"differentialX.bmp");
    sobelFilter(medianFilteredImageData, width, height);
    cout << "Ended";
    return 0;
}

我目前的图像:
水平过滤器:
this is horizontally
立式过滤器:
This is vertically
两者合在一起:
This is both together
我尝试了几乎每一个差分滤波器,但问题是一样的。也许我读错或写错了图像。但仍然垂直的滤波器工作。

bvuwiixz

bvuwiixz1#

问题似乎是存储Gx时缺少abs
outputX[y][x] = Gx替换为outputX[y][x] = abs(Gx)
我们最好也将最大值裁剪为255

outputY[y][x] = min(abs(Gy), 255);
outputX[y][x] = min(abs(Gx), 255);

我试图重现这个问题,但我在阅读写BMP图像时遇到了问题。
我使用OpenCV cv::imreadcv::imwrite进行阅读。
我使用了“水平过滤器”图像从您的职位作为一个输入。
我无法重现该问题(可能是由于不同的输入)。
完整代码:

#include <opencv2/opencv.hpp>

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
using namespace std;

void readHeaderOfAnImage(char* header, int headerSize, char* fileName) {
    ifstream fin(fileName, ios::binary);
    fin.read(header, headerSize);
    fin.close();
}

void readFileData(unsigned char** imageData, int width, int height, int headerSize, char* fileName) {
    //ifstream fin(fileName, ios::binary);
    //fin.ignore(headerSize);
    //int padding = 4 - ((width / 8) % 4);
    //unsigned char buffer = fin.get();
    //for (int i = 0, counter = 0; i < height; i++) {
    //    for (int j = 0; j < width; j++) {
    //        imageData[i][j] = buffer & (128 >> counter);
    //        ++counter;
    //        if (counter == 8) {
    //            buffer = fin.get();
    //            counter = 0;
    //        }
    //    }
    //    for (int k = 0; k < padding; ++k) fin.get();
    //}
    //fin.close();
    cv::Mat mat = cv::imread(fileName, cv::IMREAD_GRAYSCALE);
    for (int y = 0; y < height; y++) {
        memcpy(imageData[y], (unsigned char*)mat.data + y*mat.step, width);
    }
}

void writeHeaderOfAnImage(char* header, int headerSize, char* fileName) {
    ofstream fout(fileName, ios::binary);
    fout.write(header, headerSize);
    fout.close();
}

void writeDataToFile(unsigned char** imageData, int width, int height, char* fileName) {
    ofstream fout(fileName, ios::app | ios::binary);
    int padding = 4 - ((width / 8) % 4);
    unsigned char buffer = 0;
    for (int i = 0, counter = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            if (counter == 8) {//bit ended, need new one
                fout.put(buffer);
                counter = 0;
                buffer = 0;
            }
            if (imageData[i][j]) buffer = buffer | (1 << (7 - counter));//black pixel?
            counter++;
        }
        for (int k = 0; k < padding; k++) //need padding
            for (int m = 0; m < 8; m++) {
                if (counter == 8) {
                    fout.put(buffer);
                    counter = 0;
                    buffer = 0;
                }
                counter++;
            }
        if (counter == 8) {
            fout.put(buffer);
            counter = 0;
            buffer = 0;
        }
    }
    fout.close();
}

unsigned char findMedian(unsigned char arr[], int n) {
    sort(arr, arr + n);
    return arr[n / 2];
}

void medianFilter(unsigned char** imageData, unsigned char ** medianFilteredImageData, int width, int height) {
    const int kernel = 3;
    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            unsigned char window[kernel * kernel];
            int k = 0;
            for (int x = i - kernel / 2; x <= i + kernel / 2; x++) {
                for (int y = j - kernel / 2; y <= j + kernel / 2; y++) {
                    if (x >= 0 && x < height && y >= 0 && y < width) {
                        window[k] = imageData[x][y];
                        k++;
                    }
                }
            }
            medianFilteredImageData[i][j] = findMedian(window, k);
        }
    }
}

void sobelFilter(unsigned char** image, int width, int height) {
    const int vertical_kernel[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1} };
    const int horizontal_kernel[3][3] = { {1, 2, 1}, {0, 0, 0}, {-1, -2, -1} };
    unsigned char** outputX = new unsigned char* [height];
    for (int i = 0; i < height; i++) {
        outputX[i] = new unsigned char[width];
        memset(outputX[i], 60, width);
    }
    unsigned char** outputY = new unsigned char* [height];
    for (int i = 0; i < height; i++) {
        outputY[i] = new unsigned char[width];
        memset(outputY[i], 60, width);
    }
    unsigned char** filteredImage = new unsigned char* [height];
    for (int i = 0; i < height; i++) {
        filteredImage[i] = new unsigned char[width];
        memset(filteredImage[i], 60, width);
    }
    int Gx, Gy, G;
    for (int y = 1; y < height - 1; ++y) {
        for (int x = 1; x < width - 1; ++x) {
            Gx = image[y - 1][x + 1] + 2 * image[y][x + 1] + image[y + 1][x + 1]
                - image[y - 1][x - 1] - 2 * image[y][x - 1] - image[y + 1][x - 1];
            Gy = image[y + 1][x - 1] + 2 * image[y + 1][x] + image[y + 1][x + 1]
                - image[y - 1][x - 1] - 2 * image[y - 1][x] - image[y - 1][x + 1];
            G = abs(Gx) + abs(Gy);
            G = min(max(G, 0), 255);
            outputY[y][x] = min(abs(Gy), 255);
            outputX[y][x] = min(abs(Gx), 255);
            filteredImage[y][x] = G;
        }
    }

    //writeDataToFile(outputY, width, height, (char*)"differentialY.bmp");
    //writeDataToFile(outputX, width, height, (char*)"differentialX.bmp");
    //writeDataToFile(filteredImage, width, height, (char*)"differential.bmp");
    cv::Mat outputYmat = cv::Mat(height, width, CV_8UC1);//, (void*)outputY);
    cv::Mat outputXmat = cv::Mat(height, width, CV_8UC1);//, (void*)outputX);
    cv::Mat filteredImat = cv::Mat(height, width, CV_8UC1);//, (void*)filteredImage);

    for (int y = 0; y < height; y++) {
        memcpy((unsigned char*)outputYmat.data + y*width, outputY[y], width);
    }

    for (int y = 0; y < height; y++) {
        memcpy((unsigned char*)outputXmat.data + y*width, outputX[y], width);
    }

    for (int y = 0; y < height; y++) {
        memcpy((unsigned char*)filteredImat.data + y*width, filteredImage[y], width);
    }


    cv::imwrite("differentialY.bmp", outputYmat);
    cv::imwrite("differentialX.bmp", outputXmat);
    cv::imwrite("differential.bmp", filteredImat);
}


int main() {
    const int width = 3000, height = 3000, headerSize = 62;
    char imageToReadFrom[256] = "input.bmp", imageToWriteInAfterMedian[256] = "median.bmp", imageToWriteInAfterDifferential[256] = "differential.bmp";
    //cout << "Write the name of image that you want to read:\n";
    //cin >> imageToReadFrom;

    char* header = new char[headerSize];
    unsigned char** imageData = new unsigned char* [height];
    for (int i = 0; i < height; i++) imageData[i] = new unsigned char[width];
    unsigned char** medianFilteredImageData = new unsigned char* [height];
    for (int i = 0; i < height; i++) medianFilteredImageData[i] = new unsigned char[width];
    readHeaderOfAnImage(header, headerSize, imageToReadFrom);
    readFileData(imageData, width, height, headerSize, imageToReadFrom);

    cv::Mat mat = cv::Mat(height, width, CV_8UC1);
    for (int y = 0; y < height; y++) {
        memcpy((unsigned char*)mat.data + y*width, imageData[y], width);
    }
    cv::imwrite("mat.bmp", mat);

    sobelFilter(imageData, width, height);

    //medianFilter(imageData, medianFilteredImageData, width, height);
    //writeHeaderOfAnImage(header, headerSize, imageToWriteInAfterMedian);
    //writeDataToFile(medianFilteredImageData, width, height, imageToWriteInAfterMedian);
    //writeHeaderOfAnImage(header, headerSize, imageToWriteInAfterDifferential);
    //writeHeaderOfAnImage(header, headerSize, (char*)"differentialY.bmp");
    //writeHeaderOfAnImage(header, headerSize, (char*)"differentialX.bmp");
    //sobelFilter(medianFilteredImageData, width, height);
    cout << "Ended";
    return 0;
}

differentialX.bmp(PNG格式):

differentialY.bmp(PNG格式):

相关问题