图片处理与滤镜的C++实现

图片处理与滤镜的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));            }        }    }        // 高对

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容