图片处理与滤镜的C++实现
1. 基础图像类定义
<cpp>
#include <vector>#include <cmath>#include <algorithm>#include <cstring>// 像素结构体struct Pixel { unsigned char r, g, b, a; Pixel(unsigned char r = 0, unsigned char g = 0, unsigned char b = 0, unsigned char a = 255) : r(r), g(g), b(b), a(a) {}};// 图像类class Image {private: int width, height; std::vector<Pixel> pixels; public: Image(int w, int h) : width(w), height(h), pixels(w * h) {} // 获取像素 Pixel& getPixel(int x, int y) { return pixels[y * width + x]; } const Pixel& getPixel(int x, int y) const { return pixels[y * width + x]; } // 设置像素 void setPixel(int x, int y, const Pixel& p) { if (x >= 0 && x < width && y >= 0 && y < height) { pixels[y * width + x] = p; } } int getWidth() const { return width; } int getHeight() const { return height; } // 克隆图像 Image clone() const { Image newImage(width, height); newImage.pixels = pixels; return newImage; }};
2. 基础图像处理操作
2.1 亮度调整
<cpp>
class BrightnessFilter {public: // 调整亮度 (-100 到 100) static void adjustBrightness(Image& image, int brightness) { for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); p.r = clamp(p.r + brightness, 0, 255); p.g = clamp(p.g + brightness, 0, 255); p.b = clamp(p.b + brightness, 0, 255); image.setPixel(x, y, p); } } } private: static int clamp(int value, int min, int max) { return std::max(min, std::min(max, value)); }};
2.2 对比度调整
<cpp>
class ContrastFilter {public: // 调整对比度 (-100 到 100) static void adjustContrast(Image& image, float contrast) { float factor = (259.0f * (contrast + 255.0f)) / (255.0f * (259.0f - contrast)); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); p.r = clamp(factor * (p.r - 128) + 128); p.g = clamp(factor * (p.g - 128) + 128); p.b = clamp(factor * (p.b - 128) + 128); image.setPixel(x, y, p); } } } private: static int clamp(float value) { return std::max(0, std::min(255, (int)value)); }};
2.3 饱和度调整
<cpp>
class SaturationFilter {public: // 调整饱和度 (0.0 到 2.0, 1.0为原始) static void adjustSaturation(Image& image, float saturation) { for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); // 转换到HSL空间 float h, s, l; rgbToHsl(p.r / 255.0f, p.g / 255.0f, p.b / 255.0f, h, s, l); // 调整饱和度 s *= saturation; s = std::min(1.0f, s); // 转换回RGB float r, g, b; hslToRgb(h, s, l, r, g, b); p.r = r * 255; p.g = g * 255; p.b = b * 255; image.setPixel(x, y, p); } } } private: static void rgbToHsl(float r, float g, float b, float& h, float& s, float& l) { float max = std::max({r, g, b}); float min = std::min({r, g, b}); l = (max + min) / 2.0f; if (max == min) { h = s = 0; // achromatic } else { float d = max - min; s = l > 0.5f ? d / (2.0f - max - min) : d / (max + min); if (max == r) { h = (g - b) / d + (g < b ? 6.0f : 0.0f); } else if (max == g) { h = (b - r) / d + 2.0f; } else { h = (r - g) / d + 4.0f; } h /= 6.0f; } } static void hslToRgb(float h, float s, float l, float& r, float& g, float& b) { if (s == 0) { r = g = b = l; // achromatic } else { auto hue2rgb = [](float p, float q, float t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1.0f/6.0f) return p + (q - p) * 6.0f * t; if (t < 1.0f/2.0f) return q; if (t < 2.0f/3.0f) return p + (q - p) * (2.0f/3.0f - t) * 6.0f; return p; }; float q = l < 0.5f ? l * (1.0f + s) : l + s - l * s; float p = 2.0f * l - q; r = hue2rgb(p, q, h + 1.0f/3.0f); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1.0f/3.0f); } }};
3. 模糊滤镜
3.1 高斯模糊
<cpp>
class GaussianBlur {public: static void apply(Image& image, float sigma) { int kernelSize = (int)(sigma * 6) | 1; // 确保是奇数 std::vector<float> kernel = createGaussianKernel(kernelSize, sigma); Image temp = image.clone(); // 水平方向模糊 for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { applyKernelHorizontal(image, temp, x, y, kernel); } } // 垂直方向模糊 image = temp; temp = image.clone(); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { applyKernelVertical(image, temp, x, y, kernel); } } image = temp; } private: static std::vector<float> createGaussianKernel(int size, float sigma) { std::vector<float> kernel(size); float sum = 0.0f; int half = size / 2; for (int i = 0; i < size; i++) { float x = i - half; kernel[i] = exp(-(x * x) / (2.0f * sigma * sigma)); sum += kernel[i]; } // 归一化 for (int i = 0; i < size; i++) { kernel[i] /= sum; } return kernel; } static void applyKernelHorizontal(const Image& src, Image& dst, int x, int y, const std::vector<float>& kernel) { int half = kernel.size() / 2; float r = 0, g = 0, b = 0; for (int i = 0; i < kernel.size(); i++) { int sx = x + i - half; sx = std::max(0, std::min(src.getWidth() - 1, sx)); Pixel p = src.getPixel(sx, y); r += p.r * kernel[i]; g += p.g * kernel[i]; b += p.b * kernel[i]; } dst.setPixel(x, y, Pixel(r, g, b)); } static void applyKernelVertical(const Image& src, Image& dst, int x, int y, const std::vector<float>& kernel) { int half = kernel.size() / 2; float r = 0, g = 0, b = 0; for (int i = 0; i < kernel.size(); i++) { int sy = y + i - half; sy = std::max(0, std::min(src.getHeight() - 1, sy)); Pixel p = src.getPixel(x, sy); r += p.r * kernel[i]; g += p.g * kernel[i]; b += p.b * kernel[i]; } dst.setPixel(x, y, Pixel(r, g, b)); }};
3.2 运动模糊
<cpp>
class MotionBlur {public: static void apply(Image& image, int angle, int distance) { Image result = image.clone(); float rad = angle * M_PI / 180.0f; float dx = cos(rad); float dy = sin(rad); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { float r = 0, g = 0, b = 0; int count = 0; for (int i = 0; i < distance; i++) { int sx = x + (int)(dx * i); int sy = y + (int)(dy * i); if (sx >= 0 && sx < image.getWidth() && sy >= 0 && sy < image.getHeight()) { Pixel p = image.getPixel(sx, sy); r += p.r; g += p.g; b += p.b; count++; } } if (count > 0) { result.setPixel(x, y, Pixel(r/count, g/count, b/count)); } } } image = result; }};
4. 锐化滤镜
<cpp>
class SharpenFilter {public: static void apply(Image& image, float strength = 1.0f) { // 锐化卷积核 float kernel[3][3] = { {0, -1, 0}, {-1, 5, -1}, {0, -1, 0} }; // 调整强度 float center = 1 + 4 * strength; kernel[1][1] = center; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i != 1 || j != 1) { kernel[i][j] *= strength; } } } Image result = image.clone(); for (int y = 1; y < image.getHeight() - 1; y++) { for (int x = 1; x < image.getWidth() - 1; x++) { float r = 0, g = 0, b = 0; for (int ky = -1; ky <= 1; ky++) { for (int kx = -1; kx <= 1; kx++) { Pixel p = image.getPixel(x + kx, y + ky); float weight = kernel[ky + 1][kx + 1]; r += p.r * weight; g += p.g * weight; b += p.b * weight; } } result.setPixel(x, y, Pixel( std::max(0, std::min(255, (int)r)), std::max(0, std::min(255, (int)g)), std::max(0, std::min(255, (int)b)) )); } } image = result; }};
5. 边缘检测
<cpp>
class EdgeDetection {public: // Sobel边缘检测 static void sobelEdgeDetection(Image& image) { int sobelX[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1} }; int sobelY[3][3] = { {-1, -2, -1}, {0, 0, 0}, {1, 2, 1} }; Image result = image.clone(); for (int y = 1; y < image.getHeight() - 1; y++) { for (int x = 1; x < image.getWidth() - 1; x++) { int gx = 0, gy = 0; // 计算梯度 for (int ky = -1; ky <= 1; ky++) { for (int kx = -1; kx <= 1; kx++) { Pixel p = image.getPixel(x + kx, y + ky); int gray = (p.r + p.g + p.b) / 3; gx += gray * sobelX[ky + 1][kx + 1]; gy += gray * sobelY[ky + 1][kx + 1]; } } int magnitude = sqrt(gx * gx + gy * gy); magnitude = std::min(255, magnitude); result.setPixel(x, y, Pixel(magnitude, magnitude, magnitude)); } } image = result; } // Canny边缘检测 static void cannyEdgeDetection(Image& image, float lowThreshold, float highThreshold) { // 1. 高斯模糊 GaussianBlur::apply(image, 1.4f); // 2. 计算梯度 Image gradientMag(image.getWidth(), image.getHeight()); Image gradientDir(image.getWidth(), image.getHeight()); calculateGradients(image, gradientMag, gradientDir); // 3. 非极大值抑制 Image suppressed = nonMaximumSuppression(gradientMag, gradientDir); // 4. 双阈值和边缘连接 image = doubleThreshold(suppressed, lowThreshold, highThreshold); } private: static void calculateGradients(const Image& image, Image& magnitude, Image& direction) { for (int y = 1; y < image.getHeight() - 1; y++) { for (int x = 1; x < image.getWidth() - 1; x++) { // Sobel算子 int gx = 0, gy = 0; // 简化计算,只使用灰度 auto getGray = [&](int dx, int dy) { Pixel p = image.getPixel(x + dx, y + dy); return (p.r + p.g + p.b) / 3; }; gx = -getGray(-1, -1) + getGray(1, -1) + -2*getGray(-1, 0) + 2*getGray(1, 0) + -getGray(-1, 1) + getGray(1, 1); gy = -getGray(-1, -1) - 2*getGray(0, -1) - getGray(1, -1) + getGray(-1, 1) + 2*getGray(0, 1) + getGray(1, 1); float mag = sqrt(gx * gx + gy * gy); float dir = atan2(gy, gx); magnitude.setPixel(x, y, Pixel(mag, mag, mag)); direction.setPixel(x, y, Pixel(dir * 255 / (2 * M_PI), 0, 0)); } } } static Image nonMaximumSuppression(const Image& magnitude, const Image& direction) { Image result(magnitude.getWidth(), magnitude.getHeight()); for (int y = 1; y < magnitude.getHeight() - 1; y++) { for (int x = 1; x < magnitude.getWidth() - 1; x++) { float angle = direction.getPixel(x, y).r * 2 * M_PI / 255; float mag = magnitude.getPixel(x, y).r; // 将角度量化到4个方向 int dir = ((int)(angle / (M_PI / 4)) + 8) % 4; float mag1 = 0, mag2 = 0; switch(dir) { case 0: // 水平 mag1 = magnitude.getPixel(x-1, y).r; mag2 = magnitude.getPixel(x+1, y).r; break; case 1: // 45度 mag1 = magnitude.getPixel(x-1, y-1).r; mag2 = magnitude.getPixel(x+1, y+1).r; break; case 2: // 垂直 mag1 = magnitude.getPixel(x, y-1).r; mag2 = magnitude.getPixel(x, y+1).r; break; case 3: // 135度 mag1 = magnitude.getPixel(x+1, y-1).r; mag2 = magnitude.getPixel(x-1, y+1).r; break; } if (mag >= mag1 && mag >= mag2) { result.setPixel(x, y, Pixel(mag, mag, mag)); } } } return result; } static Image doubleThreshold(const Image& image, float low, float high) { Image result(image.getWidth(), image.getHeight()); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { float val = image.getPixel(x, y).r; if (val >= high) { result.setPixel(x, y, Pixel(255, 255, 255)); } else if (val >= low) { result.setPixel(x, y, Pixel(128, 128, 128)); } else { result.setPixel(x, y, Pixel(0, 0, 0)); } } } // 边缘连接 for (int y = 1; y < result.getHeight() - 1; y++) { for (int x = 1; x < result.getWidth() - 1; x++) { if (result.getPixel(x, y).r == 128) { bool hasStrongNeighbor = false; for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { if (result.getPixel(x + dx, y + dy).r == 255) { hasStrongNeighbor = true; break; } } } if (hasStrongNeighbor) { result.setPixel(x, y, Pixel(255, 255, 255)); } else { result.setPixel(x, y, Pixel(0, 0, 0)); } } } } return result; }};
6. 艺术滤镜
6.1 素描效果
<cpp>
class SketchFilter {public: static void apply(Image& image) { // 1. 转换为灰度图 Image gray = toGrayscale(image); // 2. 反色 Image inverted = invert(gray); // 3. 高斯模糊 GaussianBlur::apply(inverted, 20.0f); // 4. 颜色减淡混合 for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { int gray_val = gray.getPixel(x, y).r; int blur_val = inverted.getPixel(x, y).r; int result = gray_val + (gray_val * blur_val) / (255 - blur_val + 1); result = std::min(255, result); image.setPixel(x, y, Pixel(result, result, result)); } } } private: static Image toGrayscale(const Image& image) { Image result(image.getWidth(), image.getHeight()); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); int gray = 0.299 * p.r + 0.587 * p.g + 0.114 * p.b; result.setPixel(x, y, Pixel(gray, gray, gray)); } } return result; } static Image invert(const Image& image) { Image result(image.getWidth(), image.getHeight()); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); result.setPixel(x, y, Pixel(255 - p.r, 255 - p.g, 255 - p.b)); } } return result; }};
6.2 油画效果
<cpp>
class OilPaintingFilter {public: static void apply(Image& image, int radius = 4, int intensity = 20) { Image result = image.clone(); for (int y = radius; y < image.getHeight() - radius; y++) { for (int x = radius; x < image.getWidth() - radius; x++) { std::vector<int> intensityCount(intensity + 1, 0); std::vector<int> sumR(intensity + 1, 0); std::vector<int> sumG(intensity + 1, 0); std::vector<int> sumB(intensity + 1, 0); // 统计邻域内的颜色分布 for (int dy = -radius; dy <= radius; dy++) { for (int dx = -radius; dx <= radius; dx++) { Pixel p = image.getPixel(x + dx, y + dy); int curIntensity = ((p.r + p.g + p.b) / 3) * intensity / 255; intensityCount[curIntensity]++; sumR[curIntensity] += p.r; sumG[curIntensity] += p.g; sumB[curIntensity] += p.b; } } // 找出出现最多的强度级别 int maxCount = 0; int maxIndex = 0; for (int i = 0; i <= intensity; i++) { if (intensityCount[i] > maxCount) { maxCount = intensityCount[i]; maxIndex = i; } } // 使用该强度级别的平均颜色 if (maxCount > 0) { result.setPixel(x, y, Pixel( sumR[maxIndex] / maxCount, sumG[maxIndex] / maxCount, sumB[maxIndex] / maxCount )); } } } image = result; }};
6.3 马赛克效果
<cpp>
class MosaicFilter {public: static void apply(Image& image, int blockSize = 10) { for (int y = 0; y < image.getHeight(); y += blockSize) { for (int x = 0; x < image.getWidth(); x += blockSize) { // 计算块的平均颜色 int sumR = 0, sumG = 0, sumB = 0; int count = 0; for (int dy = 0; dy < blockSize && y + dy < image.getHeight(); dy++) { for (int dx = 0; dx < blockSize && x + dx < image.getWidth(); dx++) { Pixel p = image.getPixel(x + dx, y + dy); sumR += p.r; sumG += p.g; sumB += p.b; count++; } } if (count > 0) { Pixel avgColor(sumR / count, sumG / count, sumB / count); // 填充整个块 for (int dy = 0; dy < blockSize && y + dy < image.getHeight(); dy++) { for (int dx = 0; dx < blockSize && x + dx < image.getWidth(); dx++) { image.setPixel(x + dx, y + dy, avgColor); } } } } } }};
7. 颜色滤镜
7.1 复古滤镜
<cpp>
class VintageFilter {public: static void apply(Image& image) { for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); // 应用复古色调映射 int r = (int)(0.393 * p.r + 0.769 * p.g + 0.189 * p.b); int g = (int)(0.349 * p.r + 0.686 * p.g + 0.168 * p.b); int b = (int)(0.272 * p.r + 0.534 * p.g + 0.131 * p.b); r = std::min(255, r); g = std::min(255, g); b = std::min(255, b); image.setPixel(x, y, Pixel(r, g, b)); } } // 添加暗角效果 addVignette(image); } private: static void addVignette(Image& image) { int centerX = image.getWidth() / 2; int centerY = image.getHeight() / 2; float maxDist = sqrt(centerX * centerX + centerY * centerY); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { float dist = sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)); float factor = 1.0f - (dist / maxDist) * 0.7f; factor = std::max(0.3f, factor); Pixel p = image.getPixel(x, y); p.r *= factor; p.g *= factor; p.b *= factor; image.setPixel(x, y, p); } } }};
7.2 黑白滤镜
<cpp>
class BlackWhiteFilter {public: // 普通黑白 static void applyGrayscale(Image& image) { for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { Pixel p = image.getPixel(x, y); int gray = 0.299 * p.r + 0.587 * p.g + 0.114 * p.b; image.setPixel(x, y, Pixel(gray, gray, gray)); } } } // 高对