在OpenCV C++中如何将RGB图像转为索引色图像?现有代码仅能转灰度
Hey there! Let's tweak your code to convert that RGB image to indexed color instead of grayscale. First, a quick heads-up: OpenCV loads images in BGR format by default when using IMREAD_COLOR, so your original COLOR_RGB2GRAY should actually be COLOR_BGR2GRAY—but let's focus on the indexed color conversion.
Indexed color works by reducing the image's color palette to a fixed set (max 256 colors), then each pixel stores an index pointing to its color in that palette. Here are two practical approaches:
Approach 1: Use a Predefined Color Palette
If you want to map your image to a standard colormap (like jet, autumn, or viridis), this is a straightforward method:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; int main() { // Load the image (note: IMREAD_COLOR returns BGR, not RGB) Mat black_background = imread("image_path", IMREAD_COLOR); if (black_background.empty()) { std::cerr << "Failed to load the image!" << std::endl; return -1; } // Step 1: Convert to grayscale first (this will be our index values) Mat gray; cvtColor(black_background, gray, COLOR_BGR2GRAY); // Step 2: Generate a predefined color palette Mat palette(256, 1, CV_8UC3); int colormap = COLORMAP_JET; // Try COLORMAP_AUTUMN, COLORMAP_VIRIDIS, etc. for (int i = 0; i < 256; ++i) { Vec3b color; applyColorMap(Mat(1, 1, CV_8UC1, Scalar(i)), color, colormap); palette.at<Vec3b>(i) = color; } // Step 3: Create the indexed image and attach the palette Mat indexed_image = gray.clone(); indexed_image.setPalette(palette); // Save as PNG (supports indexed color with palettes; JPEG does not) imwrite("save_path.png", indexed_image); return 0; }
Approach 2: Quantize the Image's Own Colors (Custom Palette)
If you want to preserve the original image's color character while reducing the palette size, use k-means clustering to group similar colors:
#include <opencv2/opencv.hpp> #include <vector> #include <iostream> using namespace cv; using namespace std; int main() { // Load the image Mat black_background = imread("image_path", IMREAD_COLOR); if (black_background.empty()) { cerr << "Failed to load the image!" << endl; return -1; } // Set the number of colors in your custom palette (adjust as needed) const int num_colors = 64; // Step 1: Reshape image into a 2D array of pixels for k-means Mat pixels = black_background.reshape(1, black_background.total()); pixels.convertTo(pixels, CV_32F); // Step 2: Run k-means clustering to group similar colors vector<int> labels; Mat centers; kmeans(pixels, num_colors, labels, TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 100, 0.2), 3, KMEANS_RANDOM_CENTERS, centers); // Step 3: Convert cluster centers back to 8-bit BGR colors (our palette) centers.convertTo(centers, CV_8UC3); // Step 4: Build the indexed image (each pixel is its cluster index) Mat indexed_image(black_background.size(), CV_8UC1); int idx = 0; for (int y = 0; y < black_background.rows; ++y) { for (int x = 0; x < black_background.cols; ++x) { indexed_image.at<uchar>(y, x) = labels[idx++]; } } // Step 5: Attach the custom palette to the indexed image indexed_image.setPalette(centers); // Save as PNG to retain the indexed format imwrite("save_path.png", indexed_image); return 0; }
Important Tips:
- File Format: Always save indexed images as PNG—JPEG doesn’t support palettes and will convert back to 3-channel RGB.
- Palette Size: In Approach 2, lower
num_colorsmeans smaller file sizes but more color loss; higher values preserve more detail. - BGR vs RGB: If you need RGB instead of BGR, add
cvtColor(black_background, rgb_image, COLOR_BGR2RGB)right after loading the image.
内容的提问来源于stack exchange,提问作者SamSic

