索贝尔边缘检测器使用c++,不需要任何特殊的库或工具
Sobel edge detector using C++ without any special library or tool
我正在尝试在c++中实现SObel边缘检测器,而不使用任何特殊的图像处理库。我不知道为什么下面的代码不能完成这项工作(输出图像显示了一个混乱的灰色图片)。图像格式为PPM。如有任何建议/评论/帮助,我将不胜感激。由于
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cmath>
using namespace std;
//a class that represents the three colour values (R,G,B) in each pixel.
class Pixel { private:
unsigned int P1, P2, P3;
public:
Pixel () {};
void setPixels (unsigned int Pixel1, unsigned int Pixel2, unsigned int Pixel3);
unsigned int getPixel1 (); unsigned int getPixel2 (); unsigned int getPixel3 (); };
void Pixel::setPixels (unsigned int Pixel1, unsigned int Pixel2, unsigned int Pixel3) {
P1 = Pixel1;
P2 = Pixel2;
P3 = Pixel3; }
unsigned int Pixel::getPixel1 () {
return P1; }
unsigned int Pixel::getPixel2 () {
return P2; }
unsigned int Pixel::getPixel3 () {
return P3; }
//*****************int main () stars here! *****************
int main () {
//information contained in the header file is represented by the following variables
unsigned char Magic [2];
unsigned int TotRows = 512;
unsigned int TotCol = 512;
unsigned int MaxVal = 255;
int size = (3 * TotRows * TotCol);
char *charImage = new char [size];
//opening original image
ifstream OldImage;
OldImage.open ("image.ppm", ios::in | ios::binary);
if (!OldImage)
{
cout << "nError: Cannot open image file! " << endl;
}
//reading the header of the original image file
OldImage >> Magic [0] >> Magic [1] >> TotRows >> TotCol >> MaxVal;
OldImage.read(charImage, size);
unsigned int val1, val2, val3;
//an array of pixels, which is used to represent the image
Pixel **PixelVal;
PixelVal = new Pixel* [TotRows];
int T=0;
//Reading the image data and setting the pixels values as unsigned integers
for(int i=0; i < TotRows; i++)
{
PixelVal[i] = new Pixel [TotCol];
for(int j=0; j < TotCol; j++)
{
val1 = (unsigned int)charImage[T];
val2 = (unsigned int)charImage[T+1];
val3 = (unsigned int)charImage[T+2];
PixelVal[i][j].setPixels (val1, val2, val3);
T=T+3;
}
}
if (OldImage.fail())
{
cout << "Can't read image " << endl;
}
OldImage.close();
//Calculating the grayscale in each pixel.
//The values of the 3 colours (R, B and G) are all the same
for(int i=0; i < TotRows; i++)
{
for(int j=0; j < TotCol; j++)
{
val1=(PixelVal[i][j].getPixel1()+PixelVal[i][j].getPixel1()+PixelVal[i][j].getPixel1())/3;
val2=val1;
val3=val1;
PixelVal[i][j].setPixels(val1, val2, val3);
}
}
unsigned int valX, valY = 0; unsigned int GX [3][3]; unsigned int GY [3][3];
//Sobel Horizontal Mask
GX[0][0] = 1; GX[0][1] = 0; GX[0][2] = -1;
GX[1][0] = 2; GX[1][1] = 0; GX[1][2] = -2;
GX[2][0] = 1; GX[2][1] = 0; GX[2][2] = -1;
//Sobel Vertical Mask
GY[0][0] = 1; GY[0][1] = 2; GY[0][2] = 1;
GY[1][0] = 0; GY[1][1] = 0; GY[1][2] = 0;
GY[2][0] = -1; GY[2][1] =-2; GY[2][2] = -1;
//SOBEL edge detector implementation.
//Note: in each Pixel, the values of the 3 colours is the same.Therefore
//the calculation is performed on the first one only. The other 2 colours are
// then set to be = to the first one.
for(int i=0; i < TotRows; i++)
{
for(int j=0; j < TotCol; j++)
{
//setting the pixels around the border to 0,
//because the Sobel kernel cannot be allied to them
if ((i==0)||(i==TotRows-1)||(j==0)||(j==TotCol-1))
{
valX=0;
valY=0;
}
else
{
//calculating the X and Y convolutions
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
valX = valX + PixelVal[i+x][j+y].getPixel1() * GX[1+x][1+y];
valY = valY + PixelVal[i+x][j+y].getPixel1() * GY[1+x][1+y];
}
}
}
//Gradient magnitude
val1 = sqrt(valX*valX + valY*valY);
//setting the new pixel value
PixelVal[i][j].setPixels(val1, val1, val1);
}
}
//creating a new file to host the copied image
ofstream NewImage;
NewImage.open ("image1.ppm", ios::out | ios::binary);
if (!NewImage)
{
cout << "nError: Cannot open image file! " <<endl;
}
//writing the header in the new image file
NewImage << "P6" << endl << TotRows << " " << TotCol << " " << MaxVal << endl;
T=0;
for(int i=0; i < TotRows; i++)
{
for(int j=0; j < TotCol; j++)
{
val1 = PixelVal[i][j].getPixel1();
val2 = PixelVal[i][j].getPixel2();
val3 = PixelVal[i][j].getPixel3();
charImage[T]=(unsigned char)val1;
charImage[T+1]=(unsigned char)val2;
charImage[T+2]=(unsigned char)val3;
T=T+3;
}
}
cout << T;
NewImage.write(charImage, size);
if (NewImage.fail())
{
cout << "Can't write image " << endl;
}
NewImage.close(); delete [] charImage;
for (int i = 0; i < TotRows; i++)
{
delete [] PixelVal[i];
}
delete [] PixelVal;
return 0; }
valX
和valY
在循环中没有被归零,因此它们变得越来越大。通过将它们拟合到int中,你得到了伪随机噪声。
所有你需要做的是添加valX = valY = 0;
,你有"计算X和Y的卷积"。
相关文章:
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有类似std::lower_bound的函数,而不需要排序/分区输入
- 为什么output_editor Concept不需要output_e迭代器标记
- 在除法中不需要四舍五入
- 与C代码相比,为什么C++代码不需要"#define _POSIX_C_SOURCE 200809L"?
- 将值从另一个数组写入数组,不包括不需要的值 C++
- C++ 写入路径名中包含不需要的空字符的文件
- 是否有必要获取锁并在不需要唤醒线程时通知condition_variable?
- 使用 assimp 加载模型 - 不需要提升?
- 为什么转换函数声明不需要至少一个定义类型说明符
- 返回不需要的值的二叉搜索程序
- 当我不需要数据库中的所有值时,如何部分初始化 c++ 对象?
- C++:用户输入会产生不需要的行为
- Windows7+:如何构建不需要任何额外/外部运行时库的C++ Windows 控制台应用程序?
- 类介绍 (c++) 项目希望我们创建两个构造函数,但它们都不需要任何参数 - 我应该在这里做什么?
- 创建不需要任何进一步安装即可在其他计算机上工作的可执行文件?
- Windows中Java和C之间的任何IPC机制 - 不需要套接字
- 在c++ 11中,是否有一种方法可以在调用以任何可调用对象(包括绑定方法)作为参数的函数时不需要模板参数
- 索贝尔边缘检测器使用c++,不需要任何特殊的库或工具
- 在c++中,如何解析文本文件后面不需要的文本中的任何数据类型