3x3のソーベルフィルタを実装する。
SobelFilter.hpp
#pragma once #include <valarray>
#include <array>
//! @brief ソーベルフィルタ //! @note フィルタを変えれば他の用途にも使える class SobelFilter { // フィルタサイズ 3x3 static constexpr int FilterSize = 3; std::array < std::array<int, FilterSize>, FilterSize > filterH; //!< 水平方向 std::array < std::array<int, FilterSize>, FilterSize > filterV; //!< 垂直方向 int m_width; //!< 入出力画像の幅 int m_height; //!< 入出力画像の高さ const unsigned char* m_pimg; //!< 元画像へのポインタ // -1 →(+1)→ 0 // 0 →(+1)→ 1 // 1 →(+1)→ 2 //! @brief 水平のフィルタを取得 int fH(const int x, const int y)const { return filterH[x + 1][y + 1]; } //! @brief 垂直のフィルタを取得 int fV(const int x, const int y)const { return filterV[x + 1][y + 1]; } public: //! @brief 一画素のサイズ。RGBで3バイト static constexpr int PixelSize = 3; using Vector3d = std::valarray<int>; //! @brief [in] w 画像幅 //! @brief [in] h 画像幅 //! @brief [in] pimg 元画像へのポインタ SobelFilter(int w, int h, const unsigned char* pimg) { //ソーベルフィルタ作成 filterH[0] = { -1, 0, 1 }; filterH[1] = { -2, 0, 2 }; filterH[2] = { -1, 0, 1 }; filterV[0] = { -1,-2,-1 }; filterV[1] = { 0, 0, 0 }; filterV[2] = { 1, 2, 1 }; // 画像へアクセスする諸々の設定 m_width = w; m_height = h; m_pimg = pimg; } //! @brief 元画像の(x,y)座標の画素を取得 Vector3d pixel(const int x, const int y) { const unsigned char* p = &m_pimg[(y * m_width + x) * PixelSize]; return Vector3d({ p[0], p[1], p[2] }); } // (x,y)座標のフィルタ後の値を取得 Vector3d get(const int x, const int y) { Vector3d tmp({ 0,0,0 }); std::array<Vector3d, FilterSize * 2> px;; std::fill(px.begin(), px.end(), Vector3d{ 0,0,0 }); //水平9画素についての合計 px[0] = pixel(x - 1, y - 1) * fH(-1, -1) + pixel(x , y - 1) * fH( 0, -1) + pixel(x + 1, y - 1) * fH( 1, -1); px[1] = pixel(x - 1, y) * fH(-1, 0) + pixel(x , y) * fH( 0, 0) + pixel(x + 1, y) * fH( 1, 0); px[2] = pixel(x - 1, y + 1) * fH(-1, 1) + pixel(x , y + 1) * fH( 0, 1) + pixel(x + 1, y + 1) * fH( 1, 1); //////////////////////////////////////////////// // 垂直9画素についての合計 px[3] = pixel(x - 1, y - 1) * fV(-1, -1) + pixel(x, y - 1) * fV(0, -1) + pixel(x + 1, y - 1) * fV(1, -1); px[4] = pixel(x - 1, y) * fV(-1, 0) + pixel(x, y) * fV(0, 0) + pixel(x + 1, y) * fV(1, 0); px[5] = pixel(x - 1, y + 1) * fV(-1, 1) + pixel(x, y + 1) * fV(0, 1) + pixel(x + 1, y + 1) * fV(1, 1); for (auto& k : px) { for (int i = 0; i < PixelSize; i++) { tmp[i] += k[i]; } } for (int i = 0; i < PixelSize; i++) { tmp[i] = (tmp[i] < 0) ? 0 : tmp[i]; tmp[i] = (tmp[i] > 255) ? 255 : tmp[i]; } return tmp; } };
//! @brief width 画像横画素数 //! @brief height 画像縦画素数 //! @param [in] pimg 入力画像 //! @param [out] dst 出力先 //! @return なし void sobel( const int width, const int height, const unsigned char* pimg, unsigned char* dst ) { SobelFilter sf(width, height, pimg); size_t sz = SobelFilter::PixelSize; for (int x = 1; x < width - 1; x++) { for (int y = 1; y < height - 1; y++) { SobelFilter::Vector3d px = sf.get(x, y); for (size_t p = 0; p < sz; p++) { dst[(y * width + x) * sz + p] = px[p]; } } } }
#include <iostream> #include <vector> #include "SobelFilter.hpp" #include "NByteData.hpp" // https://www.study.suzulang.com/2dcg-functions/nbyte-data-type #include "ppmP3_read.hpp" // https://www.study.suzulang.com/cppppm-readerwriter/ppm-p3-reader-cpp void ppmP3_write( const char* const fname, const int width, const int height, const unsigned char* const p, const int vmax );
int main() { int width; int height; int vmax; unsigned char* pimg; ppmP3_read("C:\\data\\b.ppm", &width, &height, &vmax, &pimg); std::vector<unsigned char> ret(width * height * 3); sobel(width, height, pimg, ret.data()); ppmP3_write("C:\\data\\sobel.ppm", width, height, ret.data(), 255); std::cout << "Hello World!\n"; }
//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @param [in] vmax 全てのRGBの中の最大値。普通の画像なら255 //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む void ppmP3_write( const char* const fname, const int width, const int height, const unsigned char* const p, const int vmax ) { FILE* fp = fopen(fname, "wb"); fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2] ); k++; } fprintf(fp, "\n"); } fclose(fp); }